You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 16:37:01 UTC

[01/49] incubator-taverna-server git commit: taverna-* module names

Repository: incubator-taverna-server
Updated Branches:
  refs/heads/master 529e59d51 -> 8d121b2b0


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
new file mode 100644
index 0000000..adf3ea7
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
@@ -0,0 +1,769 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.getProperty;
+import static java.lang.System.out;
+import static java.lang.management.ManagementFactory.getRuntimeMXBean;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.UUID.randomUUID;
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
+import static org.apache.commons.io.FileUtils.writeLines;
+import static org.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
+import static org.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
+import static org.taverna.server.localworker.api.Constants.SUBDIR_LIST;
+import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
+import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
+import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * This class implements one side of the connection between the Taverna Server
+ * master server and this process. It delegates to a {@link Worker} instance the
+ * handling of actually running a workflow.
+ * 
+ * @author Donal Fellows
+ * @see DirectoryDelegate
+ * @see FileDelegate
+ * @see WorkerCore
+ */
+@SuppressWarnings("serial")
+public class LocalWorker extends UnicastRemoteObject implements RemoteSingleRun {
+	// ----------------------- CONSTANTS -----------------------
+
+	/** Handle to the directory containing the security info. */
+	static final File SECURITY_DIR;
+	static final String SLASHTEMP;
+	static {
+		SLASHTEMP = getProperty("java.io.tmpdir");
+		File home = new File(getProperty("user.home"));
+		// If we can't write to $HOME (i.e., we're in an odd deployment) use
+		// the official version of /tmp/$PID as a fallback.
+		if (!home.canWrite())
+			home = new File(SLASHTEMP, getRuntimeMXBean().getName());
+		SECURITY_DIR = new File(home, SECURITY_DIR_NAME);
+	}
+
+	// ----------------------- VARIABLES -----------------------
+
+	/**
+	 * Magic flag used to turn off problematic code when testing inside CI
+	 * environment.
+	 */
+	static boolean DO_MKDIR = true;
+
+	/** What to use to run a workflow engine. */
+	private final String executeWorkflowCommand;
+	/** What workflow to run. */
+	private final byte[] workflow;
+	/** The remote access object for the working directory. */
+	private final DirectoryDelegate baseDir;
+	/** What inputs to pass as files. */
+	final Map<String, String> inputFiles;
+	/** What inputs to pass as files (as file refs). */
+	final Map<String, File> inputRealFiles;
+	/** What inputs to pass as direct values. */
+	final Map<String, String> inputValues;
+	/** What delimiters to use. */
+	final Map<String, String> inputDelimiters;
+	/** The interface to the workflow engine subprocess. */
+	private final Worker core;
+	/** Our descriptor token (UUID). */
+	private final String masterToken;
+	/**
+	 * The root working directory for a workflow run, or <tt>null</tt> if it has
+	 * been deleted.
+	 */
+	private File base;
+	/**
+	 * When did this workflow start running, or <tt>null</tt> for
+	 * "never/not yet".
+	 */
+	private Date start;
+	/**
+	 * When did this workflow finish running, or <tt>null</tt> for
+	 * "never/not yet".
+	 */
+	private Date finish;
+	/** The cached status of the workflow run. */
+	RemoteStatus status;
+	/**
+	 * The name of the input Baclava document, or <tt>null</tt> to not do it
+	 * that way.
+	 */
+	String inputBaclava;
+	/**
+	 * The name of the output Baclava document, or <tt>null</tt> to not do it
+	 * that way.
+	 */
+	String outputBaclava;
+	/**
+	 * The file containing the input Baclava document, or <tt>null</tt> to not
+	 * do it that way.
+	 */
+	private File inputBaclavaFile;
+	/**
+	 * The file containing the output Baclava document, or <tt>null</tt> to not
+	 * do it that way.
+	 */
+	private File outputBaclavaFile;
+	/**
+	 * Registered shutdown hook so that we clean up when this process is killed
+	 * off, or <tt>null</tt> if that is no longer necessary.
+	 */
+	Thread shutdownHook;
+	/** Location for security information to be written to. */
+	File securityDirectory;
+	/**
+	 * Password to use to encrypt security information.
+	 */
+	char[] keystorePassword = KEYSTORE_PASSWORD;
+	/** Additional server-specified environment settings. */
+	Map<String, String> environment = new HashMap<>();
+	/** Additional server-specified java runtime settings. */
+	List<String> runtimeSettings = new ArrayList<>();
+	URL interactionFeedURL;
+	URL webdavURL;
+	URL publishURL;//FIXME
+	private boolean doProvenance = true;
+
+	// ----------------------- METHODS -----------------------
+
+	/**
+	 * @param executeWorkflowCommand
+	 *            The script used to execute workflows.
+	 * @param workflow
+	 *            The workflow to execute.
+	 * @param workerClass
+	 *            The class to instantiate as our local representative of the
+	 *            run.
+	 * @param urReceiver
+	 *            The remote class to report the generated usage record(s) to.
+	 * @param id
+	 *            The UUID to use, or <tt>null</tt> if we are to invent one.
+	 * @param seedEnvironment
+	 *            The key/value pairs to seed the worker subprocess environment
+	 *            with.
+	 * @param javaParams
+	 *            Parameters to pass to the worker subprocess java runtime
+	 *            itself.
+	 * @param workerFactory
+	 *            How to make instances of the low-level worker objects.
+	 * @throws RemoteException
+	 *             If registration of the worker fails.
+	 * @throws ImplementationException
+	 *             If something goes wrong during local setup.
+	 */
+	protected LocalWorker(String executeWorkflowCommand, byte[] workflow,
+			UsageRecordReceiver urReceiver, UUID id,
+			Map<String, String> seedEnvironment, List<String> javaParams,
+			WorkerFactory workerFactory) throws RemoteException,
+			ImplementationException {
+		super();
+		if (id == null)
+			id = randomUUID();
+		masterToken = id.toString();
+		this.workflow = workflow;
+		this.executeWorkflowCommand = executeWorkflowCommand;
+		String sharedDir = getProperty(SHARED_DIR_PROP, SLASHTEMP);
+		base = new File(sharedDir, masterToken);
+		out.println("about to create " + base);
+		try {
+			forceMkdir(base);
+			for (String subdir : SUBDIR_LIST) {
+				new File(base, subdir).mkdir();
+			}
+		} catch (IOException e) {
+			throw new ImplementationException(
+					"problem creating run working directory", e);
+		}
+		baseDir = new DirectoryDelegate(base, null);
+		inputFiles = new HashMap<>();
+		inputRealFiles = new HashMap<>();
+		inputValues = new HashMap<>();
+		inputDelimiters = new HashMap<>();
+		environment.putAll(seedEnvironment);
+		runtimeSettings.addAll(javaParams);
+		try {
+			core = workerFactory.makeInstance();
+		} catch (Exception e) {
+			out.println("problem when creating core worker implementation");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem when creating core worker implementation", e);
+		}
+		core.setURReceiver(urReceiver);
+		Thread t = new Thread(new Runnable() {
+			/**
+			 * Kill off the worker launched by the core.
+			 */
+			@Override
+			public void run() {
+				try {
+					shutdownHook = null;
+					destroy();
+				} catch (ImplementationException e) {
+					// Absolutely nothing we can do here
+				}
+			}
+		});
+		getRuntime().addShutdownHook(t);
+		shutdownHook = t;
+		status = Initialized;
+	}
+
+	@Override
+	public void destroy() throws ImplementationException {
+		killWorkflowSubprocess();
+		removeFromShutdownHooks();
+		// Is this it?
+		deleteWorkingDirectory();
+		deleteSecurityManagerDirectory();
+		core.deleteLocalResources();
+	}
+
+	private void killWorkflowSubprocess() {
+		if (status != Finished && status != Initialized)
+			try {
+				core.killWorker();
+				if (finish == null)
+					finish = new Date();
+			} catch (Exception e) {
+				out.println("problem when killing worker");
+				e.printStackTrace(out);
+			}
+	}
+
+	private void removeFromShutdownHooks() throws ImplementationException {
+		try {
+			if (shutdownHook != null)
+				getRuntime().removeShutdownHook(shutdownHook);
+		} catch (RuntimeException e) {
+			throw new ImplementationException("problem removing shutdownHook",
+					e);
+		} finally {
+			shutdownHook = null;
+		}
+	}
+
+	private void deleteWorkingDirectory() throws ImplementationException {
+		try {
+			if (base != null)
+				forceDelete(base);
+		} catch (IOException e) {
+			out.println("problem deleting working directory");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem deleting working directory", e);
+		} finally {
+			base = null;
+		}
+	}
+
+	private void deleteSecurityManagerDirectory()
+			throws ImplementationException {
+		try {
+			if (securityDirectory != null)
+				forceDelete(securityDirectory);
+		} catch (IOException e) {
+			out.println("problem deleting security directory");
+			e.printStackTrace(out);
+			throw new ImplementationException(
+					"problem deleting security directory", e);
+		} finally {
+			securityDirectory = null;
+		}
+	}
+
+	@Override
+	public void addListener(RemoteListener listener) throws RemoteException,
+			ImplementationException {
+		throw new ImplementationException("not implemented");
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		return inputBaclava;
+	}
+
+	@Override
+	public List<RemoteInput> getInputs() throws RemoteException {
+		ArrayList<RemoteInput> result = new ArrayList<>();
+		for (String name : inputFiles.keySet())
+			result.add(new InputDelegate(name));
+		return result;
+	}
+
+	@Override
+	public List<String> getListenerTypes() {
+		return emptyList();
+	}
+
+	@Override
+	public List<RemoteListener> getListeners() {
+		return singletonList(core.getDefaultListener());
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		return outputBaclava;
+	}
+
+	class SecurityDelegate extends UnicastRemoteObject implements
+			RemoteSecurityContext {
+		private void setPrivatePerms(File dir) {
+			if (!dir.setReadable(false, false) || !dir.setReadable(true, true)
+					|| !dir.setExecutable(false, false)
+					|| !dir.setExecutable(true, true)
+					|| !dir.setWritable(false, false)
+					|| !dir.setWritable(true, true)) {
+				out.println("warning: "
+						+ "failed to set permissions on security context directory");
+			}
+		}
+
+		protected SecurityDelegate(String token) throws IOException {
+			super();
+			if (DO_MKDIR) {
+				securityDirectory = new File(SECURITY_DIR, token);
+				forceMkdir(securityDirectory);
+				setPrivatePerms(securityDirectory);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The bytes to put in the file.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, byte[] data) throws RemoteException,
+				ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeByteArrayToFile(f, data);
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The lines to put in the file. The
+		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
+		 *            will be used to do the writing.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, Collection<String> data)
+				throws RemoteException, ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeLines(f, SYSTEM_ENCODING, data);
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		/**
+		 * Write some data to a given file in the context directory.
+		 * 
+		 * @param name
+		 *            The name of the file to write.
+		 * @param data
+		 *            The line to put in the file. The
+		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
+		 *            will be used to do the writing.
+		 * @throws RemoteException
+		 *             If anything goes wrong.
+		 * @throws ImplementationException
+		 */
+		protected void write(String name, char[] data) throws RemoteException,
+				ImplementationException {
+			try {
+				File f = new File(securityDirectory, name);
+				writeLines(f, SYSTEM_ENCODING, asList(new String(data)));
+			} catch (IOException e) {
+				throw new ImplementationException("problem writing " + name, e);
+			}
+		}
+
+		@Override
+		public void setKeystore(byte[] keystore) throws RemoteException,
+				ImplementationException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (keystore == null)
+				throw new IllegalArgumentException("keystore may not be null");
+			write(KEYSTORE_FILE, keystore);
+		}
+
+		@Override
+		public void setPassword(char[] password) throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (password == null)
+				throw new IllegalArgumentException("password may not be null");
+			keystorePassword = password.clone();
+		}
+
+		@Override
+		public void setTruststore(byte[] truststore) throws RemoteException,
+				ImplementationException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (truststore == null)
+				throw new IllegalArgumentException("truststore may not be null");
+			write(TRUSTSTORE_FILE, truststore);
+		}
+
+		@Override
+		public void setUriToAliasMap(Map<URI, String> uriToAliasMap)
+				throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			if (uriToAliasMap == null)
+				return;
+			ArrayList<String> lines = new ArrayList<>();
+			for (Entry<URI, String> site : uriToAliasMap.entrySet())
+				lines.add(site.getKey().toASCIIString() + " " + site.getValue());
+			// write(URI_ALIAS_MAP, lines);
+		}
+
+		@Override
+		public void setHelioToken(String helioToken) throws RemoteException {
+			if (status != Initialized)
+				throw new RemoteException("not initializing");
+			out.println("registering HELIO CIS token for export");
+			environment.put(HELIO_TOKEN_NAME, helioToken);
+		}
+	}
+
+	@Override
+	public RemoteSecurityContext getSecurityContext() throws RemoteException,
+			ImplementationException {
+		try {
+			return new SecurityDelegate(masterToken);
+		} catch (RemoteException e) {
+			if (e.getCause() != null)
+				throw new ImplementationException(
+						"problem initializing security context", e.getCause());
+			throw e;
+		} catch (IOException e) {
+			throw new ImplementationException(
+					"problem initializing security context", e);
+		}
+	}
+
+	@Override
+	public RemoteStatus getStatus() {
+		// only state that can spontaneously change to another
+		if (status == Operating) {
+			status = core.getWorkerStatus();
+			if (status == Finished && finish == null)
+				finish = new Date();
+		}
+		return status;
+	}
+
+	@Override
+	public RemoteDirectory getWorkingDirectory() {
+		return baseDir;
+	}
+
+	File validateFilename(String filename) throws RemoteException {
+		if (filename == null)
+			throw new IllegalArgumentException("filename must be non-null");
+		try {
+			return getValidatedFile(base, filename.split("/"));
+		} catch (IOException e) {
+			throw new IllegalArgumentException("failed to validate filename", e);
+		}
+	}
+
+	class InputDelegate extends UnicastRemoteObject implements RemoteInput {
+		private String name;
+
+		InputDelegate(String name) throws RemoteException {
+			super();
+			this.name = name;
+			if (!inputFiles.containsKey(name)) {
+				if (status != Initialized)
+					throw new IllegalStateException("not initializing");
+				inputFiles.put(name, null);
+				inputRealFiles.put(name, null);
+				inputValues.put(name, null);
+				inputDelimiters.put(name, null);
+			}
+		}
+
+		@Override
+		public String getFile() {
+			return inputFiles.get(name);
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public String getValue() {
+			return inputValues.get(name);
+		}
+
+		@Override
+		public String getDelimiter() throws RemoteException {
+			return inputDelimiters.get(name);
+		}
+
+		@Override
+		public void setFile(String file) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			inputRealFiles.put(name, validateFilename(file));
+			inputValues.put(name, null);
+			inputFiles.put(name, file);
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setValue(String value) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			inputValues.put(name, value);
+			inputFiles.put(name, null);
+			inputRealFiles.put(name, null);
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setDelimiter(String delimiter) throws RemoteException {
+			if (status != Initialized)
+				throw new IllegalStateException("not initializing");
+			if (inputBaclava != null)
+				throw new IllegalStateException("input baclava file set");
+			if (delimiter != null) {
+				if (delimiter.length() > 1)
+					throw new IllegalStateException(
+							"multi-character delimiter not permitted");
+				if (delimiter.charAt(0) == 0)
+					throw new IllegalStateException(
+							"may not use NUL for splitting");
+				if (delimiter.charAt(0) > 127)
+					throw new IllegalStateException(
+							"only ASCII characters supported for splitting");
+			}
+			inputDelimiters.put(name, delimiter);
+		}
+	}
+
+	@Override
+	public RemoteInput makeInput(String name) throws RemoteException {
+		return new InputDelegate(name);
+	}
+
+	@Override
+	public RemoteListener makeListener(String type, String configuration)
+			throws RemoteException {
+		throw new RemoteException("listener manufacturing unsupported");
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename) throws RemoteException {
+		if (status != Initialized)
+			throw new IllegalStateException("not initializing");
+		inputBaclavaFile = validateFilename(filename);
+		for (String input : inputFiles.keySet()) {
+			inputFiles.put(input, null);
+			inputRealFiles.put(input, null);
+			inputValues.put(input, null);
+		}
+		inputBaclava = filename;
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename) throws RemoteException {
+		if (status != Initialized)
+			throw new IllegalStateException("not initializing");
+		if (filename != null)
+			outputBaclavaFile = validateFilename(filename);
+		else
+			outputBaclavaFile = null;
+		outputBaclava = filename;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean prov) {
+		doProvenance = prov;
+	}
+
+	@Override
+	public void setStatus(RemoteStatus newStatus)
+			throws IllegalStateTransitionException, RemoteException,
+			ImplementationException, StillWorkingOnItException {
+		if (status == newStatus)
+			return;
+
+		switch (newStatus) {
+		case Initialized:
+			throw new IllegalStateTransitionException(
+					"may not move back to start");
+		case Operating:
+			switch (status) {
+			case Initialized:
+				boolean started;
+				try {
+					started = createWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem creating executing workflow", e);
+				}
+				if (!started)
+					throw new StillWorkingOnItException(
+							"workflow start in process");
+				break;
+			case Stopped:
+				try {
+					core.startWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem continuing workflow run", e);
+				}
+				break;
+			case Finished:
+				throw new IllegalStateTransitionException("already finished");
+			default:
+				break;
+			}
+			status = Operating;
+			break;
+		case Stopped:
+			switch (status) {
+			case Initialized:
+				throw new IllegalStateTransitionException(
+						"may only stop from Operating");
+			case Operating:
+				try {
+					core.stopWorker();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem stopping workflow run", e);
+				}
+				break;
+			case Finished:
+				throw new IllegalStateTransitionException("already finished");
+			default:
+				break;
+			}
+			status = Stopped;
+			break;
+		case Finished:
+			switch (status) {
+			case Operating:
+			case Stopped:
+				try {
+					core.killWorker();
+					if (finish == null)
+						finish = new Date();
+				} catch (Exception e) {
+					throw new ImplementationException(
+							"problem killing workflow run", e);
+				}
+			default:
+				break;
+			}
+			status = Finished;
+			break;
+		}
+	}
+
+	private boolean createWorker() throws Exception {
+		start = new Date();
+		char[] pw = keystorePassword;
+		keystorePassword = null;
+		/*
+		 * Do not clear the keystorePassword array here; its ownership is
+		 * *transferred* to the worker core which doesn't copy it but *does*
+		 * clear it after use.
+		 */
+		return core.initWorker(this, executeWorkflowCommand, workflow, base,
+				inputBaclavaFile, inputRealFiles, inputValues, inputDelimiters,
+				outputBaclavaFile, securityDirectory, pw, doProvenance,
+				environment, masterToken, runtimeSettings);
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		return finish == null ? null : new Date(finish.getTime());
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		return start == null ? null : new Date(start.getTime());
+	}
+
+	@Override
+	public void setInteractionServiceDetails(URL feed, URL webdav, URL publish) {
+		interactionFeedURL = feed;
+		webdavURL = webdav;
+		publishURL = publish;
+	}
+
+	@Override
+	public void ping() {
+		// Do nothing here; this *should* be empty
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
new file mode 100644
index 0000000..03ee69d
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.exit;
+import static java.lang.System.getProperty;
+import static java.lang.System.out;
+import static java.lang.System.setProperty;
+import static java.lang.System.setSecurityManager;
+import static java.rmi.registry.LocateRegistry.getRegistry;
+import static org.taverna.server.localworker.api.Constants.DEATH_DELAY;
+import static org.taverna.server.localworker.api.Constants.LOCALHOST;
+import static org.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
+import static org.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
+import static org.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
+import static org.taverna.server.localworker.api.Constants.UNSECURE_PROP;
+
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.rmi.RMISecurityManager;
+import java.rmi.RemoteException;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.taverna.server.localworker.api.RunAccounting;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+
+/**
+ * The registered factory for runs, this class is responsible for constructing
+ * runs that are suitable for particular users. It is also the entry point for
+ * this whole process.
+ * 
+ * @author Donal Fellows
+ * @see LocalWorker
+ */
+@SuppressWarnings("serial")
+public class TavernaRunManager extends UnicastRemoteObject implements
+		RemoteRunFactory, RunAccounting, WorkerFactory {
+	String command;
+	Map<String, String> seedEnvironment = new HashMap<>();
+	List<String> javaInitParams = new ArrayList<>();
+	private WorkflowBundleIO io;
+	private int activeRuns = 0;
+	// Hacks!
+	public static String interactionHost;
+	public static String interactionPort;
+	public static String interactionWebdavPath;
+	public static String interactionFeedPath;
+
+	/**
+	 * How to get the actual workflow document from the XML document that it is
+	 * contained in.
+	 * 
+	 * @param containerDocument
+	 *            The document sent from the web interface.
+	 * @return The element describing the workflow, as expected by the Taverna
+	 *         command line executor.
+	 */
+	protected Element unwrapWorkflow(Document containerDocument) {
+		return (Element) containerDocument.getDocumentElement().getFirstChild();
+	}
+
+	private static final String usage = "java -jar server.worker.jar workflowExecScript ?-Ekey=val...? ?-Jconfig? UUID";
+
+	/**
+	 * An RMI-enabled factory for runs.
+	 * 
+	 * @param command
+	 *            What command to call to actually run a run.
+	 * @throws RemoteException
+	 *             If anything goes wrong during creation of the instance.
+	 */
+	public TavernaRunManager(String command) throws RemoteException {
+		this.command = command;
+		this.io = new WorkflowBundleIO();
+	}
+
+	@Override
+	public RemoteSingleRun make(byte[] workflow, String creator,
+			UsageRecordReceiver urReceiver, UUID id) throws RemoteException {
+		if (creator == null)
+			throw new RemoteException("no creator");
+		try {
+			URI wfid = io.readBundle(new ByteArrayInputStream(workflow), null)
+					.getMainWorkflow().getWorkflowIdentifier();
+			out.println("Creating run from workflow <" + wfid + "> for <"
+					+ creator + ">");
+			return new LocalWorker(command, workflow, urReceiver, id,
+					seedEnvironment, javaInitParams, this);
+		} catch (RemoteException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new RemoteException("bad instance construction", e);
+		}
+	}
+
+	private static boolean shuttingDown;
+	private static String factoryName;
+	private static Registry registry;
+
+	static synchronized void unregisterFactory() {
+		if (!shuttingDown) {
+			shuttingDown = true;
+			try {
+				if (factoryName != null && registry != null)
+					registry.unbind(factoryName);
+			} catch (Exception e) {
+				e.printStackTrace(out);
+			}
+		}
+	}
+
+	@Override
+	public void shutdown() {
+		unregisterFactory();
+		new Thread(new DelayedDeath()).start();
+	}
+
+	static class DelayedDeath implements Runnable {
+		@Override
+		public void run() {
+			try {
+				Thread.sleep(DEATH_DELAY);
+			} catch (InterruptedException e) {
+			} finally {
+				exit(0);
+			}
+		}
+	}
+
+	private void addArgument(String arg) {
+		if (arg.startsWith("-E")) {
+			String trimmed = arg.substring(2);
+			int idx = trimmed.indexOf('=');
+			if (idx > 0) {
+				addEnvironmentDefinition(trimmed.substring(0, idx),
+						trimmed.substring(idx + 1));
+				return;
+			}
+		} else if (arg.startsWith("-D")) {
+			if (arg.indexOf('=') > 0) {
+				addJavaParameter(arg);
+				return;
+			}
+		} else if (arg.startsWith("-J")) {
+			addJavaParameter(arg.substring(2));
+			return;
+		}
+		throw new IllegalArgumentException("argument \"" + arg
+				+ "\" must start with -D, -E or -J; "
+				+ "-D and -E must contain a \"=\"");
+	}
+
+	/**
+	 * @param args
+	 *            The arguments from the command line invocation.
+	 * @throws Exception
+	 *             If we can't connect to the RMI registry, or if we can't read
+	 *             the workflow, or if we can't build the worker instance, or
+	 *             register it. Also if the arguments are wrong.
+	 */
+	public static void main(String[] args) throws Exception {
+		if (args.length < 2)
+			throw new Exception("wrong # args: must be \"" + usage + "\"");
+		if (!getProperty(UNSECURE_PROP, "no").equals("yes")) {
+			setProperty(SEC_POLICY_PROP, LocalWorker.class.getClassLoader()
+					.getResource(SECURITY_POLICY_FILE).toExternalForm());
+			setProperty(RMI_HOST_PROP, LOCALHOST);
+		}
+		setSecurityManager(new RMISecurityManager());
+		factoryName = args[args.length - 1];
+		TavernaRunManager man = new TavernaRunManager(args[0]);
+		for (int i = 1; i < args.length - 1; i++)
+			man.addArgument(args[i]);
+		registry = getRegistry(LOCALHOST);
+
+		registry.bind(factoryName, man);
+		getRuntime().addShutdownHook(new Thread() {
+			@Override
+			public void run() {
+				unregisterFactory();
+			}
+		});
+		out.println("registered RemoteRunFactory with ID " + factoryName);
+	}
+
+	private void addJavaParameter(String string) {
+		this.javaInitParams.add(string);
+	}
+
+	private void addEnvironmentDefinition(String key, String value) {
+		this.seedEnvironment.put(key, value);
+	}
+
+	@Override
+	public void setInteractionServiceDetails(String host, String port,
+			String webdavPath, String feedPath) throws RemoteException {
+		if (host == null || port == null || webdavPath == null
+				|| feedPath == null)
+			throw new IllegalArgumentException("all params must be non-null");
+		interactionHost = host;
+		interactionPort = port;
+		interactionWebdavPath = webdavPath;
+		interactionFeedPath = feedPath;
+	}
+
+	@Override
+	public synchronized int countOperatingRuns() {
+		return (activeRuns < 0 ? 0 : activeRuns);
+	}
+
+	@Override
+	public synchronized void runStarted() {
+		activeRuns++;
+	}
+
+	@Override
+	public synchronized void runCeased() {
+		activeRuns--;
+	}
+
+	@Override
+	public Worker makeInstance() throws Exception {
+		return new WorkerCore(this);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
new file mode 100644
index 0000000..1a6cff8
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.io.File.createTempFile;
+import static java.io.File.pathSeparator;
+import static java.lang.Boolean.parseBoolean;
+import static java.lang.Double.parseDouble;
+import static java.lang.Integer.parseInt;
+import static java.lang.Long.parseLong;
+import static java.lang.Runtime.getRuntime;
+import static java.lang.System.out;
+import static java.net.InetAddress.getLocalHost;
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.sizeOfDirectory;
+import static org.apache.commons.io.FileUtils.write;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
+import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.DEATH_TIME;
+import static org.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
+import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
+import static org.taverna.server.localworker.api.Constants.START_WAIT_TIME;
+import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
+import static org.taverna.server.localworker.api.Constants.TIME;
+import static org.taverna.server.localworker.impl.Status.Aborted;
+import static org.taverna.server.localworker.impl.Status.Completed;
+import static org.taverna.server.localworker.impl.Status.Failed;
+import static org.taverna.server.localworker.impl.Status.Held;
+import static org.taverna.server.localworker.impl.Status.Started;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
+import static org.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
+import static org.taverna.server.localworker.impl.WorkerCore.pmap;
+import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
+import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
+import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
+import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.ws.Holder;
+
+import org.ogf.usage.JobUsageRecord;
+import org.taverna.server.localworker.api.RunAccounting;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.impl.utils.TimingOutTask;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * The core class that connects to a Taverna command-line workflow execution
+ * engine. This implementation always registers a single listener, &lquo;
+ * <tt>io</tt> &rquo;, with two properties representing the stdout and stderr of
+ * the run and one representing the exit code. The listener is
+ * remote-accessible. It does not support attaching any other listeners.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class WorkerCore extends UnicastRemoteObject implements Worker,
+		RemoteListener {
+	@Nonnull
+	static final Map<String, Property> pmap = new HashMap<>();
+	/**
+	 * Regular expression to extract the detailed timing information from the
+	 * output of /usr/bin/time
+	 */
+	@Nonnull
+	private static final Pattern TimeRE;
+	static {
+		final String TIMERE = "([0-9.:]+)";
+		final String TERMS = "(real|user|system|sys|elapsed)";
+		TimeRE = Pattern.compile(TIMERE + " *" + TERMS + "[ \t]*" + TIMERE
+				+ " *" + TERMS + "[ \t]*" + TIMERE + " *" + TERMS);
+	}
+
+	/**
+	 * Environment variables to remove before any fork (because they're large or
+	 * potentially leaky).
+	 */
+	// TODO Conduct a proper survey of what to remove
+	@Nonnull
+	private static final String[] ENVIRONMENT_TO_REMOVE = { "SUDO_COMMAND",
+			"SUDO_USER", "SUDO_GID", "SUDO_UID", "DISPLAY", "LS_COLORS",
+			"XFILESEARCHPATH", "SSH_AGENT_PID", "SSH_AUTH_SOCK" };
+
+	@Nullable
+	Process subprocess;
+	@Nonnull
+	final StringWriter stdout;
+	@Nonnull
+	final StringWriter stderr;
+	@Nullable
+	Integer exitCode;
+	boolean readyToSendEmail;
+	@Nullable
+	String emailAddress;
+	@Nullable
+	Date start;
+	@Nonnull
+	final RunAccounting accounting;
+	@Nonnull
+	final Holder<Integer> pid;
+
+	private boolean finished;
+	@Nullable
+	private JobUsageRecord ur;
+	@Nullable
+	private File wd;
+	@Nullable
+	private UsageRecordReceiver urreceiver;
+	@Nullable
+	private File workflowFile;
+	private boolean stopped;
+
+	/**
+	 * @param accounting
+	 *            Object that looks after how many runs are executing.
+	 * @throws RemoteException
+	 */
+	public WorkerCore(@Nonnull RunAccounting accounting) throws RemoteException {
+		super();
+		stdout = new StringWriter();
+		stderr = new StringWriter();
+		pid = new Holder<>();
+		this.accounting = accounting;
+	}
+
+	private int getPID() {
+		synchronized (pid) {
+			if (pid.value == null)
+				return -1;
+			return pid.value;
+		}
+	}
+
+	/**
+	 * Fire up the workflow. This causes a transition into the operating state.
+	 * 
+	 * @param executeWorkflowCommand
+	 *            The command to run to execute the workflow.
+	 * @param workflow
+	 *            The workflow document to execute.
+	 * @param workingDir
+	 *            What directory to use as the working directory.
+	 * @param inputBaclava
+	 *            The baclava file to use for inputs, or <tt>null</tt> to use
+	 *            the other <b>input*</b> arguments' values.
+	 * @param inputFiles
+	 *            A mapping of input names to files that supply them. Note that
+	 *            we assume that nothing mapped here will be mapped in
+	 *            <b>inputValues</b>.
+	 * @param inputValues
+	 *            A mapping of input names to values to supply to them. Note
+	 *            that we assume that nothing mapped here will be mapped in
+	 *            <b>inputFiles</b>.
+	 * @param outputBaclava
+	 *            What baclava file to write the output from the workflow into,
+	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
+	 *            subdirectory.
+	 * @param token
+	 *            The name of the workflow run.
+	 * @return <tt>true</tt> if the worker started, or <tt>false</tt> if a
+	 *         timeout occurred.
+	 * @throws IOException
+	 *             If any of quite a large number of things goes wrong.
+	 */
+	@Override
+	public boolean initWorker(
+			@Nonnull final LocalWorker local,
+			@Nonnull final String executeWorkflowCommand,
+			@Nonnull final byte[] workflow,
+			@Nonnull final File workingDir,
+			@Nullable final File inputBaclava,
+			@Nonnull final Map<String, File> inputFiles,
+			@Nonnull final Map<String, String> inputValues, 
+			@Nonnull final Map<String, String> inputDelimiters,
+			@Nullable final File outputBaclava,
+			@Nonnull final File securityDir,
+			@Nullable final char[] password,
+			final boolean generateProvenance,
+			@Nonnull final Map<String, String> environment,
+			@Nullable final String token,
+			@Nonnull final List<String> runtime) throws IOException {
+		try {
+			new TimingOutTask() {
+				@Override
+				public void doIt() throws IOException {
+					startExecutorSubprocess(
+							createProcessBuilder(local, executeWorkflowCommand,
+									workflow, workingDir, inputBaclava,
+									inputFiles, inputValues, inputDelimiters,
+									outputBaclava, securityDir, password,
+									generateProvenance, environment, token,
+									runtime), password);
+				}
+			}.doOrTimeOut(START_WAIT_TIME);
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException(e);
+		}
+		return subprocess != null;
+	}
+
+	private void startExecutorSubprocess(@Nonnull ProcessBuilder pb,
+			@Nullable char[] password) throws IOException {
+		// Start the subprocess
+		out.println("starting " + pb.command() + " in directory "
+				+ pb.directory() + " with environment " + pb.environment());
+		subprocess = pb.start();
+		if (subprocess == null)
+			throw new IOException("unknown failure creating process");
+		start = new Date();
+		accounting.runStarted();
+
+		// Capture its stdout and stderr
+		new AsyncCopy(subprocess.getInputStream(), stdout, pid);
+		new AsyncCopy(subprocess.getErrorStream(), stderr);
+		if (password != null)
+			new PasswordWriterThread(subprocess, password);
+	}
+
+	/**
+	 * Assemble the process builder. Does not launch the subprocess.
+	 * 
+	 * @param local
+	 *            The local worker container.
+	 * @param executeWorkflowCommand
+	 *            The reference to the workflow engine implementation.
+	 * @param workflow
+	 *            The workflow to execute.
+	 * @param workingDir
+	 *            The working directory to use.
+	 * @param inputBaclava
+	 *            What file to read a baclava document from (or <tt>null</tt>)
+	 * @param inputFiles
+	 *            The mapping from inputs to files.
+	 * @param inputValues
+	 *            The mapping from inputs to literal values.
+	 * @param outputBaclava
+	 *            What file to write a baclava document to (or <tt>null</tt>)
+	 * @param securityDir
+	 *            The credential manager directory.
+	 * @param password
+	 *            The password for the credential manager.
+	 * @param environment
+	 *            The seed environment
+	 * @param token
+	 *            The run identifier that the server wants to use.
+	 * @param runtime
+	 *            Any runtime parameters to Java.
+	 * @return The configured process builder.
+	 * @throws IOException
+	 *             If file handling fails
+	 * @throws UnsupportedEncodingException
+	 *             If we can't encode any text (unlikely)
+	 * @throws FileNotFoundException
+	 *             If we can't write the workflow out (unlikely)
+	 */
+	@Nonnull
+	ProcessBuilder createProcessBuilder(@Nonnull LocalWorker local,
+			@Nonnull String executeWorkflowCommand, @Nonnull byte[] workflow,
+			@Nonnull File workingDir, @Nullable File inputBaclava,
+			@Nonnull Map<String, File> inputFiles,
+			@Nonnull Map<String, String> inputValues,
+			@Nonnull Map<String, String> inputDelimiters,
+			@Nullable File outputBaclava, @Nonnull File securityDir,
+			@Nonnull char[] password, boolean generateProvenance,
+			@Nonnull Map<String, String> environment, @Nonnull String token,
+			@Nonnull List<String> runtime) throws IOException,
+			UnsupportedEncodingException, FileNotFoundException {
+		ProcessBuilder pb = new ProcessBuilder();
+		pb.command().add(TIME);
+		/*
+		 * WARNING! HERE THERE BE DRAGONS! BE CAREFUL HERE!
+		 * 
+		 * Work around _Maven_ bug with permissions in zip files! The executable
+		 * bit is stripped by Maven's handling of file permissions, and there's
+		 * no practical way to work around it without massively increasing the
+		 * pain in other ways. Only want this on Unix - Windows isn't affected
+		 * by this - so we use the file separator as a proxy for whether this is
+		 * a true POSIX system. Ugly! Ugly ugly ugly...
+		 * 
+		 * http://jira.codehaus.org/browse/MASSEMBLY-337 is relevant, but not
+		 * the whole story as we don't want to use a non-standard packaging
+		 * method as there's a real chance of it going wrong in an unexpected
+		 * way then. Other parts of the story are that the executable bit isn't
+		 * preserved when unpacking with the dependency plugin, and there's no
+		 * way to be sure that the servlet container will preserve the bit
+		 * either (as that's probably using a Java-based ZIP engine).
+		 */
+		if (File.separatorChar == '/')
+			pb.command().add("/bin/sh");
+		pb.command().add(executeWorkflowCommand);
+		if (runtime != null)
+			pb.command().addAll(runtime);
+
+		// Enable verbose logging
+		pb.command().add("-logfile");
+		pb.command().add(
+				new File(new File(workingDir, "logs"), "detail.log")
+						.getAbsolutePath());
+
+		if (securityDir != null) {
+			pb.command().add(CREDENTIAL_MANAGER_DIRECTORY);
+			pb.command().add(securityDir.getAbsolutePath());
+			out.println("security dir location: " + securityDir);
+		}
+		if (password != null) {
+			pb.command().add(CREDENTIAL_MANAGER_PASSWORD);
+			out.println("password of length " + password.length
+					+ " will be written to subprocess stdin");
+		}
+
+		// Add arguments denoting inputs
+		if (inputBaclava != null) {
+			pb.command().add("-inputdoc");
+			pb.command().add(inputBaclava.getAbsolutePath());
+			if (!inputBaclava.exists())
+				throw new IOException("input baclava file doesn't exist");
+		} else {
+			for (Entry<String, File> port : inputFiles.entrySet()) {
+				if (port.getValue() == null)
+					continue;
+				pb.command().add("-inputfile");
+				pb.command().add(port.getKey());
+				pb.command().add(port.getValue().getAbsolutePath());
+				if (!port.getValue().exists())
+					throw new IOException("input file for port \"" + port
+							+ "\" doesn't exist");
+			}
+			for (Entry<String, String> port : inputValues.entrySet()) {
+				if (port.getValue() == null)
+					continue;
+				pb.command().add("-inputfile");
+				pb.command().add(port.getKey());
+				File f = createTempFile(".tav_in_", null, workingDir);
+				pb.command().add(f.getAbsolutePath());
+				write(f, port.getValue(), "UTF-8");
+			}
+			for (Entry<String, String> delim : inputDelimiters.entrySet()) {
+				if (delim.getValue() == null)
+					continue;
+				pb.command().add("-inputdelimiter");
+				pb.command().add(delim.getKey());
+				pb.command().add(delim.getValue());
+			}
+		}
+
+		// Add arguments denoting outputs
+		if (outputBaclava != null) {
+			pb.command().add("-outputdoc");
+			pb.command().add(outputBaclava.getAbsolutePath());
+			if (!outputBaclava.getParentFile().exists())
+				throw new IOException(
+						"parent directory of output baclava file does not exist");
+			if (outputBaclava.exists())
+				throw new IOException("output baclava file exists");
+			// Provenance cannot be supported when using baclava output
+		} else {
+			File out = new File(workingDir, "out");
+			if (!out.mkdir())
+				throw new IOException("failed to make output directory \"out\"");
+			// Taverna needs the dir to *not* exist now
+			forceDelete(out);
+			pb.command().add("-outputdir");
+			pb.command().add(out.getAbsolutePath());
+			// Enable provenance generation
+			if (generateProvenance) {
+				pb.command().add("-embedded");
+				pb.command().add("-provenance");
+				pb.command().add("-provbundle");
+				pb.command().add("out.bundle.zip");
+			}
+		}
+
+		// Add an argument holding the workflow
+		File tmp = createTempFile(".wf_", ".scufl2", workingDir);
+		try (OutputStream os = new FileOutputStream(tmp)) {
+			os.write(workflow);
+		}
+		pb.command().add(workflowFile.getAbsolutePath());
+
+		// Indicate what working directory to use
+		pb.directory(workingDir);
+		wd = workingDir;
+
+		Map<String, String> env = pb.environment();
+		for (String name : ENVIRONMENT_TO_REMOVE)
+			env.remove(name);
+
+		// Merge any options we have had imposed on us from outside
+		env.putAll(environment);
+
+		// Patch the environment to deal with TAVUTILS-17
+		assert env.get("PATH") != null;
+		env.put("PATH", new File(System.getProperty("java.home"), "bin")
+				+ pathSeparator + env.get("PATH"));
+		// Patch the environment to deal with TAVSERV-189
+		env.put("TAVERNA_APPHOME", workingDir.getCanonicalPath());
+		// Patch the environment to deal with TAVSERV-224
+		env.put("TAVERNA_RUN_ID", token);
+		if (interactionHost != null || local.interactionFeedURL != null
+				|| local.webdavURL != null) {
+			env.put("INTERACTION_HOST", makeInterHost(local.interactionFeedURL));
+			env.put("INTERACTION_PORT", makeInterPort(local.interactionFeedURL));
+			env.put("INTERACTION_FEED", makeInterPath(local.interactionFeedURL));
+			env.put("INTERACTION_WEBDAV",
+					local.webdavURL != null ? local.webdavURL.getPath()
+							: interactionWebdavPath);
+			String pub = makeInterPublish(local.publishURL);
+			if (pub != null && !pub.isEmpty())
+				env.put("INTERACTION_PUBLISH", pub);
+		}
+		return pb;
+	}
+
+	@Nullable
+	private static String makeInterHost(@Nullable URL url) {
+		if (url == null)
+			return interactionHost;
+		return url.getProtocol() + "://" + url.getHost();
+	}
+
+	@Nullable
+	private static String makeInterPort(@Nullable URL url) {
+		if (url == null)
+			return interactionPort;
+		int port = url.getPort();
+		if (port == -1)
+			port = url.getDefaultPort();
+		return Integer.toString(port);
+	}
+
+	@Nullable
+	private static String makeInterPublish(@Nullable URL url)
+			throws IOException {
+		if (url == null)
+			return null;
+		try {
+			URI uri = url.toURI();
+			int port = uri.getPort();
+			if (port == -1)
+				return uri.getScheme() + "://" + uri.getHost();
+			else
+				return uri.getScheme() + "://" + uri.getHost() + ":" + port;
+		} catch (URISyntaxException e) {
+			throw new IOException("problem constructing publication url", e);
+		}
+	}
+
+	@Nullable
+	private static String makeInterPath(@Nullable URL url) {
+		if (url == null)
+			return interactionFeedPath;
+		return url.getPath();
+	}
+
+	/**
+	 * Kills off the subprocess if it exists and is alive.
+	 */
+	@Override
+	public void killWorker() {
+		if (!finished && subprocess != null) {
+			final Holder<Integer> code = new Holder<>();
+			for (TimingOutTask tot : new TimingOutTask[] { new TimingOutTask() {
+				/** Check if the workflow terminated of its own accord */
+				@Override
+				public void doIt() throws IOException {
+					code.value = subprocess.exitValue();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Failed, code.value);
+				}
+			}, new TimingOutTask() {
+				/** Tell the workflow to stop */
+				@Override
+				public void doIt() throws IOException {
+					code.value = killNicely();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Aborted, code.value);
+				}
+			}, new TimingOutTask() {
+				/** Kill the workflow, kill it with fire */
+				@Override
+				public void doIt() throws IOException {
+					code.value = killHard();
+					accounting.runCeased();
+					buildUR(code.value == 0 ? Completed : Aborted, code.value);
+				}
+			} }) {
+				try {
+					tot.doOrTimeOut(DEATH_TIME);
+				} catch (Exception e) {
+				}
+				if (code.value != null)
+					break;
+			}
+			finished = true;
+			setExitCode(code.value);
+			readyToSendEmail = true;
+		}
+	}
+
+	/**
+	 * Integrated spot to handle writing/logging of the exit code.
+	 * 
+	 * @param code
+	 *            The exit code.
+	 */
+	private void setExitCode(int code) {
+		exitCode = code;
+		if (code > 256 - 8) {
+			out.println("workflow aborted, Raven issue = " + (code - 256));
+		} else if (code > 128) {
+			out.println("workflow aborted, signal=" + (code - 128));
+		} else {
+			out.println("workflow exited, code=" + code);
+		}
+	}
+
+	@Nonnull
+	private JobUsageRecord newUR() throws DatatypeConfigurationException {
+		try {
+			if (wd != null)
+				return new JobUsageRecord(wd.getName());
+		} catch (RuntimeException e) {
+		}
+		return new JobUsageRecord("unknown");
+	}
+
+	/**
+	 * Fills in the accounting information from the exit code and stderr.
+	 * 
+	 * @param exitCode
+	 *            The exit code from the program.
+	 */
+	private void buildUR(@Nonnull Status status, int exitCode) {
+		try {
+			Date now = new Date();
+			long user = -1, sys = -1, real = -1;
+			Matcher m = TimeRE.matcher(stderr.toString());
+			ur = newUR();
+			while (m.find())
+				for (int i = 1; i < 6; i += 2)
+					if (m.group(i + 1).equals("user"))
+						user = parseDuration(m.group(i));
+					else if (m.group(i + 1).equals("sys")
+							|| m.group(i + 1).equals("system"))
+						sys = parseDuration(m.group(i));
+					else if (m.group(i + 1).equals("real")
+							|| m.group(i + 1).equals("elapsed"))
+						real = parseDuration(m.group(i));
+			if (user != -1)
+				ur.addCpuDuration(user).setUsageType("user");
+			if (sys != -1)
+				ur.addCpuDuration(sys).setUsageType("system");
+			ur.addUser(System.getProperty("user.name"), null);
+			ur.addStartAndEnd(start, now);
+			if (real != -1)
+				ur.addWallDuration(real);
+			else
+				ur.addWallDuration(now.getTime() - start.getTime());
+			ur.setStatus(status.toString());
+			ur.addHost(getLocalHost().getHostName());
+			ur.addResource("exitcode", Integer.toString(exitCode));
+			ur.addDisk(sizeOfDirectory(wd)).setStorageUnit("B");
+			if (urreceiver != null)
+				urreceiver.acceptUsageRecord(ur.marshal());
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	private long parseDuration(@Nonnull String durationString) {
+		try {
+			return (long) (parseDouble(durationString) * 1000);
+		} catch (NumberFormatException nfe) {
+			// Not a double; maybe MM:SS.mm or HH:MM:SS.mm
+		}
+		long dur = 0;
+		for (String d : durationString.split(":"))
+			try {
+				dur = 60 * dur + parseLong(d);
+			} catch (NumberFormatException nfe) {
+				// Assume that only one thing is fractional, and that it is last
+				return 60000 * dur + (long) (parseDouble(d) * 1000);
+			}
+		return dur * 1000;
+	}
+
+	private void signal(@Nonnull String signal) throws Exception {
+		int pid = getPID();
+		if (pid > 0
+				&& getRuntime().exec("kill -" + signal + " " + pid).waitFor() == 0)
+			return;
+		throw new Exception("failed to send signal " + signal + " to process "
+				+ pid);
+	}
+
+	@Nullable
+	private Integer killNicely() {
+		try {
+			signal("TERM");
+			return subprocess.waitFor();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	@Nullable
+	private Integer killHard() {
+		try {
+			signal("QUIT");
+			return subprocess.waitFor();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Move the worker out of the stopped state and back to operating.
+	 * 
+	 * @throws Exception
+	 *             if it fails.
+	 */
+	@Override
+	public void startWorker() throws Exception {
+		signal("CONT");
+		stopped = false;
+	}
+
+	/**
+	 * Move the worker into the stopped state from the operating state.
+	 * 
+	 * @throws Exception
+	 *             if it fails.
+	 */
+	@Override
+	public void stopWorker() throws Exception {
+		signal("STOP");
+		stopped = true;
+	}
+
+	/**
+	 * @return The status of the workflow run. Note that this can be an
+	 *         expensive operation.
+	 */
+	@Override
+	public RemoteStatus getWorkerStatus() {
+		if (subprocess == null)
+			return Initialized;
+		if (finished)
+			return Finished;
+		try {
+			setExitCode(subprocess.exitValue());
+		} catch (IllegalThreadStateException e) {
+			if (stopped)
+				return Stopped;
+			return Operating;
+		}
+		finished = true;
+		readyToSendEmail = true;
+		accounting.runCeased();
+		buildUR(exitCode.intValue() == 0 ? Completed : Failed, exitCode);
+		return Finished;
+	}
+
+	@Override
+	public String getConfiguration() {
+		return "";
+	}
+
+	@Override
+	public String getName() {
+		return DEFAULT_LISTENER_NAME;
+	}
+
+	@Override
+	public String getProperty(String propName) throws RemoteException {
+		switch (Property.is(propName)) {
+		case STDOUT:
+			return stdout.toString();
+		case STDERR:
+			return stderr.toString();
+		case EXIT_CODE:
+			return (exitCode == null) ? "" : exitCode.toString();
+		case EMAIL:
+			return emailAddress;
+		case READY_TO_NOTIFY:
+			return Boolean.toString(readyToSendEmail);
+		case USAGE:
+			try {
+				JobUsageRecord toReturn;
+				if (subprocess == null) {
+					toReturn = newUR();
+					toReturn.setStatus(Held.toString());
+				} else if (ur == null) {
+					toReturn = newUR();
+					toReturn.setStatus(Started.toString());
+					toReturn.addStartAndEnd(start, new Date());
+					toReturn.addUser(System.getProperty("user.name"), null);
+				} else {
+					toReturn = ur;
+				}
+				/*
+				 * Note that this record is not to be pushed to the server. That
+				 * is done elsewhere (when a proper record is produced)
+				 */
+				return toReturn.marshal();
+			} catch (Exception e) {
+				e.printStackTrace();
+				return "";
+			}
+		default:
+			throw new RemoteException("unknown property");
+		}
+	}
+
+	@Override
+	public String getType() {
+		return DEFAULT_LISTENER_NAME;
+	}
+
+	@Override
+	public String[] listProperties() {
+		return Property.names();
+	}
+
+	@Override
+	public void setProperty(String propName, String value)
+			throws RemoteException {
+		switch (Property.is(propName)) {
+		case EMAIL:
+			emailAddress = value;
+			return;
+		case READY_TO_NOTIFY:
+			readyToSendEmail = parseBoolean(value);
+			return;
+		case STDOUT:
+		case STDERR:
+		case EXIT_CODE:
+		case USAGE:
+			throw new RemoteException("property is read only");
+		default:
+			throw new RemoteException("unknown property");
+		}
+	}
+
+	@Override
+	public RemoteListener getDefaultListener() {
+		return this;
+	}
+
+	@Override
+	public void setURReceiver(@Nonnull UsageRecordReceiver receiver) {
+		urreceiver = receiver;
+	}
+
+	@Override
+	public void deleteLocalResources() throws ImplementationException {
+		try {
+			if (workflowFile != null && workflowFile.getParentFile().exists())
+				forceDelete(workflowFile);
+		} catch (IOException e) {
+			throw new ImplementationException("problem deleting workflow file",
+					e);
+		}
+	}
+}
+
+/**
+ * An engine for asynchronously copying from an {@link InputStream} to a
+ * {@link Writer}.
+ * 
+ * @author Donal Fellows
+ */
+class AsyncCopy extends Thread {
+	@Nonnull
+	private BufferedReader from;
+	@Nonnull
+	private Writer to;
+	@Nullable
+	private Holder<Integer> pidHolder;
+
+	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to)
+			throws UnsupportedEncodingException {
+		this(from, to, null);
+	}
+
+	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to,
+			@Nullable Holder<Integer> pid) throws UnsupportedEncodingException {
+		this.from = new BufferedReader(new InputStreamReader(from,
+				SYSTEM_ENCODING));
+		this.to = to;
+		this.pidHolder = pid;
+		setDaemon(true);
+		start();
+	}
+
+	@Override
+	public void run() {
+		try {
+			if (pidHolder != null) {
+				String line = from.readLine();
+				if (line.matches("^pid:\\d+$"))
+					synchronized (pidHolder) {
+						pidHolder.value = parseInt(line.substring(4));
+					}
+				else
+					to.write(line + System.getProperty("line.separator"));
+			}
+			copy(from, to);
+		} catch (IOException e) {
+		}
+	}
+}
+
+/**
+ * A helper for asynchronously writing a password to a subprocess's stdin.
+ * 
+ * @author Donal Fellows
+ */
+class PasswordWriterThread extends Thread {
+	private OutputStream to;
+	private char[] chars;
+
+	PasswordWriterThread(@Nonnull Process to, @Nonnull char[] chars) {
+		this.to = to.getOutputStream();
+		assert chars != null;
+		this.chars = chars;
+		setDaemon(true);
+		start();
+	}
+
+	@Override
+	public void run() {
+		try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(to,
+				SYSTEM_ENCODING))) {
+			pw.println(chars);
+		} catch (UnsupportedEncodingException e) {
+			// Not much we can do here
+			e.printStackTrace();
+		} finally {
+			/*
+			 * We don't trust GC to clear password from memory. We also take
+			 * care not to clear the default password!
+			 */
+			if (chars != KEYSTORE_PASSWORD)
+				Arrays.fill(chars, '\00');
+		}
+	}
+}
+
+enum Property {
+	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
+			"readyToNotify"), EMAIL("notificationAddress"), USAGE("usageRecord");
+
+	private String s;
+
+	private Property(String s) {
+		this.s = s;
+		pmap.put(s, this);
+	}
+
+	@Override
+	public String toString() {
+		return s;
+	}
+
+	public static Property is(@Nonnull String s) {
+		return pmap.get(s);
+	}
+
+	@Nonnull
+	public static String[] names() {
+		return pmap.keySet().toArray(new String[pmap.size()]);
+	}
+}
+
+enum Status {
+	Aborted, Completed, Failed, Held, Queued, Started, Suspended
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
new file mode 100644
index 0000000..fbc3a72
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Utility class that handles filename validation on different target platforms.
+ * 
+ * @author Donal Fellows.
+ */
+public abstract class FilenameVerifier {
+	private FilenameVerifier(){}
+
+	static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
+
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_NAMES = new HashSet<String>(){{
+		add("");
+		add("..");
+		add(".");
+		if (IS_WINDOWS) {
+			add("con");
+			add("prn");
+			add("nul");
+			add("aux");
+			for (int i = 1; i <= 9; i++) {
+				add("com" + i);
+				add("lpt" + i);
+			}
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<Character> ILLEGAL_CHARS = new HashSet<Character>(){{
+		add('/');
+		for (char i=0 ; i<32 ; i++)
+			add(i);
+		if (IS_WINDOWS) {
+			add('\\');
+			add('>');
+			add('<');
+			add(':');
+			add('"');
+			add('|');
+			add('?');
+			add('*');
+		} else {
+			add(' '); // whitespace; too much trouble from these
+			add('\t');
+			add('\r');
+			add('\n');
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_PREFIXES = new HashSet<String>(){{
+		if (IS_WINDOWS) {
+			add("con.");
+			add("prn.");
+			add("nul.");
+			add("aux.");
+			for (int i = 1; i <= 9; i++) {
+				add("com" + i + ".");
+				add("lpt" + i + ".");
+			}
+		}
+	}};
+	@SuppressWarnings("serial")
+	private static final Set<String> ILLEGAL_SUFFIXES = new HashSet<String>(){{
+		if (IS_WINDOWS) {
+			add(" ");
+			add(".");
+		}
+	}};
+
+	/**
+	 * Construct a file handle, applying platform-specific filename validation
+	 * rules in the process.
+	 * 
+	 * @param dir
+	 *            The directory acting as a root, which is assumed to be
+	 *            correctly named. May be <tt>null</tt>.
+	 * @param names
+	 *            The names of filename fragments to apply the checks to. Must
+	 *            have at least one value.
+	 * @return The file handle. Never <tt>null</tt>.
+	 * @throws IOException
+	 *             If validation fails.
+	 */
+	public static File getValidatedFile(File dir, String... names)
+			throws IOException {
+		if (names.length == 0)
+			throw new IOException("empty filename");
+		File f = dir;
+		for (String name : names) {
+			String low = name.toLowerCase();
+			if (ILLEGAL_NAMES.contains(low))
+				throw new IOException("illegal filename");
+			for (char c : ILLEGAL_CHARS)
+				if (low.indexOf(c) >= 0)
+					throw new IOException("illegal filename");
+			for (String s : ILLEGAL_PREFIXES)
+				if (low.startsWith(s))
+					throw new IOException("illegal filename");
+			for (String s : ILLEGAL_SUFFIXES)
+				if (low.endsWith(s))
+					throw new IOException("illegal filename");
+			f = new File(f, name);
+		}
+		assert f != null;
+		return f;
+	}
+
+	/**
+	 * Create a file handle where the underlying file must exist.
+	 * 
+	 * @param dir
+	 *            The directory that will contain the file.
+	 * @param name
+	 *            The name of the file; will be validated.
+	 * @return The handle.
+	 * @throws IOException
+	 *             If validation fails or the file doesn't exist.
+	 */
+	public static File getValidatedExistingFile(File dir, String name)
+			throws IOException {
+		File f = getValidatedFile(dir, name);
+		if (!f.exists())
+			throw new IOException("doesn't exist");
+		return f;
+	}
+
+	/**
+	 * Create a file handle where the underlying file must <i>not</i> exist.
+	 * 
+	 * @param dir
+	 *            The directory that will contain the file.
+	 * @param name
+	 *            The name of the file; will be validated.
+	 * @return The handle. The file will not be created by this method.
+	 * @throws IOException
+	 *             If validation fails or the file does exist.
+	 */
+	public static File getValidatedNewFile(File dir, String name)
+			throws IOException {
+		File f = getValidatedFile(dir, name);
+		if (f.exists())
+			throw new IOException("already exists");
+		return f;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
new file mode 100644
index 0000000..3dd3ac1
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
@@ -0,0 +1,40 @@
+package org.taverna.server.localworker.impl.utils;
+
+import javax.annotation.Nullable;
+
+/**
+ * A class that handles running a task that can take some time.
+ * 
+ * @author Donal Fellows
+ * 
+ */
+public abstract class TimingOutTask extends Thread {
+	public abstract void doIt() throws Exception;
+
+	@Nullable
+	private Exception ioe;
+
+	@Override
+	public final void run() {
+		try {
+			doIt();
+		} catch (Exception ioe) {
+			this.ioe = ioe;
+		}
+	}
+
+	public TimingOutTask() {
+		this.setDaemon(true);
+	}
+
+	public void doOrTimeOut(long timeout) throws Exception {
+		start();
+		try {
+			join(timeout);
+		} catch (InterruptedException e) {
+			interrupt();
+		}
+		if (ioe != null)
+			throw ioe;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/resources/security.policy
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/resources/security.policy b/taverna-server-worker/src/main/resources/security.policy
new file mode 100644
index 0000000..5b5c322
--- /dev/null
+++ b/taverna-server-worker/src/main/resources/security.policy
@@ -0,0 +1,11 @@
+//keystore "signers.jks";
+//grant signedBy "taverna" {
+//   permission java.util.PropertyPermission "*", "read,write";
+//   permission java.lang.RuntimePermission "shutdownHooks";
+//   permission java.lang.RuntimePermission "exitVM";
+//   permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute,delete";
+//   permission java.net.SocketPermission "localhost:1024-" "accept,connect,listen";
+//};
+grant {
+   permission java.security.AllPermission "*:*";
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java b/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
new file mode 100644
index 0000000..7bcd92e
--- /dev/null
+++ b/taverna-server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.util.UUID.randomUUID;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.localworker.api.Worker;
+import org.taverna.server.localworker.api.WorkerFactory;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+public class LocalWorkerTest {
+	LocalWorker lw;
+	static List<String> events;
+
+	public static RemoteStatus returnThisStatus = RemoteStatus.Operating;
+
+	static class DummyWorker implements Worker {
+		@Override
+		public RemoteListener getDefaultListener() {
+			return new RemoteListener() {
+				@Override
+				public String getConfiguration() {
+					return "RLCONFIG";
+				}
+
+				@Override
+				public String getName() {
+					return "RLNAME";
+				}
+
+				@Override
+				public String getProperty(String propName) {
+					return "RLPROP[" + propName + "]";
+				}
+
+				@Override
+				public String getType() {
+					return "RLTYPE";
+				}
+
+				@Override
+				public String[] listProperties() {
+					return new String[] { "RLP1", "RLP2" };
+				}
+
+				@Override
+				public void setProperty(String propName, String value) {
+					events.add("setProperty[");
+					events.add(propName);
+					events.add(value);
+					events.add("]");
+				}
+			};
+		}
+
+		@Override
+		public RemoteStatus getWorkerStatus() {
+			events.add("status=" + returnThisStatus);
+			return returnThisStatus;
+		}
+
+		@Override
+		public boolean initWorker(LocalWorker local,
+				String executeWorkflowCommand, byte[] workflow,
+				File workingDir, File inputBaclava,
+				Map<String, File> inputFiles, Map<String, String> inputValues,
+				Map<String, String> delimiters, File outputBaclava, File cmdir,
+				char[] cmpass, boolean doprov, Map<String, String> env,
+				String id, List<String> conf) throws Exception {
+			events.add("init[");
+			events.add(executeWorkflowCommand);
+			events.add(new String(workflow, "UTF-8"));
+			int dirLen = workingDir.getName().length();
+			events.add(Integer.toString(dirLen));
+			events.add(inputBaclava == null ? "<null>" : inputBaclava
+					.toString().substring(dirLen));
+			Map<String, String> in = new TreeMap<>();
+			for (Entry<String, File> name : inputFiles.entrySet())
+				in.put(name.getKey(), name.getValue() == null ? "<null>" : name
+						.getValue().getName());
+			events.add(in.toString());
+			events.add(new TreeMap<>(inputValues).toString());
+			events.add(outputBaclava == null ? "<null>" : outputBaclava
+					.getName());
+			// TODO: check cmdir and cmpass
+			// TODO: check doprov
+			// TODO: log env
+			// TODO: check delimiters
+			events.add("]");
+			return true;
+		}
+
+		@Override
+		public void killWorker() throws Exception {
+			events.add("kill");
+		}
+
+		@Override
+		public void startWorker() throws Exception {
+			events.add("start");
+		}
+
+		@Override
+		public void stopWorker() throws Exception {
+			events.add("stop");
+		}
+
+		@Override
+		public void setURReceiver(UsageRecordReceiver receiver) {
+			// We just ignore this
+		}
+
+		@Override
+		public void deleteLocalResources() throws ImplementationException {
+			// Nothing to do here
+		}
+	}
+
+	WorkerFactory factory = new WorkerFactory() {
+		@Override
+		public Worker makeInstance() throws Exception {
+			return new DummyWorker();
+		}
+	};
+
+	@Before
+	public void setUp() throws Exception {
+		lw = new LocalWorker("XWC", "WF".getBytes("UTF-8"), null, randomUUID(),
+				new HashMap<String, String>(), new ArrayList<String>(), factory);
+		events = new ArrayList<>();
+		returnThisStatus = RemoteStatus.Operating;
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		lw.destroy();
+	}
+
+	private List<String> l(String... strings) {
+		return Arrays.asList(strings);
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	@Test
+	public void testDestroy1() throws Exception {
+		lw.destroy();
+		assertEquals(l(), events);
+	}
+
+	@Test
+	public void testDestroy2() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+	}
+
+	@Test
+	public void testDestroy3() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "kill"), events);
+	}
+
+	@Test
+	public void testDestroy4() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+		lw.destroy();
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "kill"), events);
+	}
+
+	@Test
+	public void testAddListener() {
+		Throwable t = null;
+		try {
+			lw.addListener(null);
+		} catch (Throwable caught) {
+			t = caught;
+		}
+		assertNotNull(t);
+		assertSame(ImplementationException.class, t.getClass());
+		assertNotNull(t.getMessage());
+		assertEquals("not implemented", t.getMessage());
+	}
+
+	@Test
+	public void testGetInputBaclavaFile() throws Exception {
+		assertNull(lw.getInputBaclavaFile());
+		lw.setInputBaclavaFile("IBaclava");
+		assertNotNull(lw.getInputBaclavaFile());
+		assertEquals("IBaclava", lw.getInputBaclavaFile());
+		lw.makeInput("FOO").setValue("BAR");
+		assertNull(lw.getInputBaclavaFile());
+	}
+
+	@Test
+	public void testGetInputsWithValue() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		lw.makeInput("FOO").setValue("BAR");
+
+		assertEquals(1, lw.getInputs().size());
+		assertEquals("FOO", lw.getInputs().get(0).getName());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNotNull(lw.getInputs().get(0).getValue());
+
+		lw.setInputBaclavaFile("BLAH");
+
+		assertEquals(1, lw.getInputs().size());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+	}
+
+	@Test
+	public void testGetInputsWithFile() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		lw.makeInput("BAR").setFile("FOO");
+
+		assertEquals(1, lw.getInputs().size());
+		assertEquals("BAR", lw.getInputs().get(0).getName());
+		assertNotNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+
+		lw.setInputBaclavaFile("BLAH");
+
+		assertEquals(1, lw.getInputs().size());
+		assertNull(lw.getInputs().get(0).getFile());
+		assertNull(lw.getInputs().get(0).getValue());
+	}
+
+	@Test
+	public void testGetListenerTypes() {
+		assertEquals("[]", lw.getListenerTypes().toString());
+	}
+
+	@Test
+	public void testGetListeners() throws Exception {
+		assertEquals(1, lw.getListeners().size());
+		RemoteListener rl = lw.getListeners().get(0);
+		assertEquals("RLNAME", rl.getName());
+		assertEquals("RLCONFIG", rl.getConfiguration());
+		assertEquals("RLTYPE", rl.getType());
+		assertEquals("[RLP1, RLP2]", Arrays.asList(rl.listProperties())
+				.toString());
+		assertEquals("RLPROP[RLP1]", rl.getProperty("RLP1"));
+		assertEquals("RLPROP[RLP2]", rl.getProperty("RLP2"));
+		rl.setProperty("FOOBAR", "BARFOO");
+		assertEquals(l("setProperty[", "FOOBAR", "BARFOO", "]"), events);
+	}
+
+	@Test
+	public void testGetOutputBaclavaFile() throws Exception {
+		assertNull(lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile("notnull");
+		assertEquals("notnull", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile(null);
+		assertNull(lw.getOutputBaclavaFile());
+	}
+
+	@Test
+	public void testGetSecurityContext() throws Exception {
+		boolean md = DO_MKDIR;
+		LocalWorker.DO_MKDIR = false; // HACK! Work around Hudson problem...
+		try {
+			assertNotNull(lw.getSecurityContext());
+		} finally {
+			LocalWorker.DO_MKDIR = md;
+		}
+	}
+
+	@Test
+	public void testGetStatusInitial() {
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+	}
+
+	@Test
+	public void testGetStatus() throws Exception {
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+		returnThisStatus = RemoteStatus.Operating;
+		assertEquals(RemoteStatus.Initialized, lw.getStatus());
+		lw.setStatus(RemoteStatus.Operating);
+		assertEquals(RemoteStatus.Operating, lw.getStatus());
+		assertEquals(RemoteStatus.Operating, lw.getStatus());
+		returnThisStatus = RemoteStatus.Finished;
+		assertEquals(RemoteStatus.Finished, lw.getStatus());
+		returnThisStatus = RemoteStatus.Stopped;
+		assertEquals(RemoteStatus.Finished, lw.getStatus());
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "status=Operating", "status=Operating",
+						"status=Finished"), events);
+	}
+
+	@Test
+	public void testGetWorkingDirectory() throws Exception {
+		RemoteDirectory rd = lw.getWorkingDirectory();
+		assertNotNull(rd);
+		assertNotNull(rd.getContents());
+		assertNull(rd.getContainingDirectory());
+		assertNotNull(rd.getName());
+		assertEquals(-1, rd.getName().indexOf('/'));
+		assertFalse("..".equals(rd.getName()));
+		assertEquals("", rd.getName());
+	}
+
+	@Test
+	public void testValidateFilename() throws Exception {
+		lw.validateFilename("foobar");
+		lw.validateFilename("foo/bar");
+		lw.validateFilename("foo.bar");
+		lw.validateFilename("foo..bar");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad0() throws Exception {
+		lw.validateFilename("./.");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad1() throws Exception {
+		lw.validateFilename("/");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad2() throws Exception {
+		lw.validateFilename("");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad3() throws Exception {
+		lw.validateFilename(null);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad4() throws Exception {
+		lw.validateFilename("..");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testValidateFilenameBad5() throws Exception {
+		lw.validateFilename("foo/../bar");
+	}
+
+	@Test
+	public void testMakeInput() throws Exception {
+		assertEquals(0, lw.getInputs().size());
+
+		RemoteInput ri = lw.makeInput("TEST");
+
+		assertNotNull(ri);
+		assertEquals(1, lw.getInputs().size());
+		assertNotSame(ri, lw.getInputs().get(0)); // different delegates
+		assertEquals("TEST", ri.getName());
+		assertNull(ri.getFile());
+		assertNull(ri.getValue());
+
+		lw.setInputBaclavaFile("bad");
+		ri.setFile("good");
+		assertEquals("good", ri.getFile());
+		assertNull(lw.getInputBaclavaFile());
+		ri.setValue("very good");
+		assertEquals("very good", ri.getValue());
+		assertNull(ri.getFile());
+		assertNull(lw.getInputBaclavaFile());
+
+		lw.makeInput("TEST2");
+		assertEquals(2, lw.getInputs().size());
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testMakeInputFileSanity() throws Exception {
+		lw.makeInput("foo").setFile("/../bar");
+	}
+
+	@Test
+	public void testMakeListener() {
+		Throwable t = null;
+		try {
+			lw.makeListener("?", "?");
+		} catch (Throwable caught) {
+			t = caught;
+		}
+		assertNotNull(t);
+		assertSame(RemoteException.class, t.getClass());
+		assertNotNull(t.getMessage());
+		assertEquals("listener manufacturing unsupported", t.getMessage());
+	}
+
+	@Test
+	public void testSetInputBaclavaFile1() throws Exception {
+		assertNull(lw.getInputBaclavaFile());
+		lw.setInputBaclavaFile("eg");
+		assertEquals("eg", lw.getInputBaclavaFile());
+	}
+
+	@Test
+	public void testSetInputBaclavaFile2() throws Exception {
+		RemoteInput ri = lw.makeInput("foo");
+		ri.setValue("bar");
+		assertEquals("bar", ri.getValue());
+		lw.setInputBaclavaFile("eg");
+		assertNull(ri.getValue());
+	}
+
+	@Test
+	public void testSetOutputBaclavaFile1() throws Exception {
+		assertNull(lw.outputBaclava);
+		lw.setOutputBaclavaFile("foobar");
+		assertEquals("foobar", lw.outputBaclava);
+		assertEquals("foobar", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile("foo/bar");
+		assertEquals("foo/bar", lw.outputBaclava);
+		assertEquals("foo/bar", lw.getOutputBaclavaFile());
+		lw.setOutputBaclavaFile(null);
+		assertNull(lw.outputBaclava);
+		assertNull(lw.getOutputBaclavaFile());
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testSetOutputBaclavaFile2() throws Exception {
+		lw.setOutputBaclavaFile("/foobar");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testSetOutputBaclavaFile3() throws Exception {
+		lw.setOutputBaclavaFile("foo/../bar");
+	}
+
+	@Test
+	public void testSetStatus0() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "start", "kill"), events);
+	}
+
+	@Test
+	public void testSetStatus1() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
+						"]", "stop", "kill"), events);
+	}
+
+	@Test
+	public void testSetStatus2() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Finished);
+		assertEquals(l(), events);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus3() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus4() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus5() throws Exception {
+		lw.setStatus(RemoteStatus.Initialized);
+		lw.setStatus(RemoteStatus.Stopped);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus6() throws Exception {
+		lw.setStatus(RemoteStatus.Finished);
+		lw.setStatus(RemoteStatus.Stopped);
+	}
+
+	@Test(expected = IllegalStateTransitionException.class)
+	public void testSetStatus7() throws Exception {
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Stopped);
+		lw.setStatus(RemoteStatus.Initialized);
+	}
+
+	@Test
+	public void testLifecycle() throws Exception {
+		lw.makeInput("foo").setFile("foofile");
+		lw.makeInput("bar").setValue("barvalue");
+		lw.setOutputBaclavaFile("spong");
+		lw.setOutputBaclavaFile("boo");
+		lw.setStatus(RemoteStatus.Operating);
+		lw.setStatus(RemoteStatus.Finished);
+		// Assumes order of map, so fragile but works...
+		assertEquals(
+				l("init[", "XWC", "WF", "36", "<null>",
+						"{bar=<null>, foo=foofile}",
+						"{bar=barvalue, foo=null}", "boo", "]", "kill"), events);
+	}
+}


[22/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/src/test/java/SerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-execution-delegate/src/test/java/SerializationTest.java b/taverna-server-execution-delegate/src/test/java/SerializationTest.java
new file mode 100644
index 0000000..c4bf0b9
--- /dev/null
+++ b/taverna-server-execution-delegate/src/test/java/SerializationTest.java
@@ -0,0 +1,54 @@
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.execution_delegate.RemoteExecution.WorkflowReportDocument;
+
+public class SerializationTest {
+	private static final boolean PRINT = true;
+	SchemaOutputResolver sink;
+	StringWriter schema;
+
+	String schema() {
+		return schema.toString();
+	}
+
+	@Before
+	public void init() {
+		schema = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(schema);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+		assertEquals("", schema());
+	}
+
+	@Test
+	public void testSchemaGeneration() throws JAXBException, IOException {
+		JAXBContext.newInstance(WorkflowReportDocument.class).generateSchema(
+				sink);
+		assertFalse("generated schema must be non-empty", schema().isEmpty());
+		assertTrue(
+				"generated schema must define workflowReport element",
+				schema().contains(
+						"<xs:element name=\"workflowReport\" type=\"WorkflowReport\"/>\n"));
+		if (PRINT)
+			System.out.print(schema());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/.gitignore b/taverna-server-port-description/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-port-description/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/pom.xml b/taverna-server-port-description/pom.xml
new file mode 100644
index 0000000..99582ed
--- /dev/null
+++ b/taverna-server-port-description/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-port-description</artifactId>
+	<name>Apache Taverna Server Workflow Port Descriptor Types</name>
+	<description>The structural types used to describe ports on workflows, as exported by Taverna Server.</description>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+	<build>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-eclipse-plugin</artifactId>
+					<configuration>
+						<projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
new file mode 100644
index 0000000..2ea392f
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "AbsentValue")
+public class AbsentValue extends AbstractValue {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
new file mode 100644
index 0000000..e57c4f9
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlID;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "Port")
+public class AbstractPort {
+	@XmlID
+	@XmlAttribute(required = true)
+	public String name;
+
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer depth;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
new file mode 100644
index 0000000..7c3fe9a
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "PortDescription")
+public abstract class AbstractPortDescription {
+	@XmlAttribute
+	public String workflowId;
+	@XmlAttribute
+	@XmlSchemaType(name = "anyURI")
+	public URI workflowRun;
+	@XmlAttribute
+	public String workflowRunId;
+
+	public void fillInBaseData(String docId, String runId, URI runUrl) {
+		this.workflowId = docId;
+		this.workflowRun = runUrl;
+		this.workflowRunId = runId;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
new file mode 100644
index 0000000..47232c2
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "Value")
+@XmlSeeAlso( { ErrorValue.class, LeafValue.class, ListValue.class, AbsentValue.class })
+public abstract class AbstractValue {
+	@XmlAttribute(namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI href;
+
+	public void setAddress(URI uri, String localAddress) {
+		if (uri.getPath().endsWith("/")) {
+			href = URI.create(uri + "wd/out/" + localAddress);
+		} else {
+			href = URI.create(uri + "/wd/out/" + localAddress);
+		}
+		//about = "out/" + localAddress;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
new file mode 100644
index 0000000..0bb07b4
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "ErrorValue")
+public class ErrorValue extends AbstractValue {
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer depth;
+	@XmlAttribute(name = "errorFile")
+	public String fileName;
+	@XmlAttribute(name = "errorByteLength")
+	public Long byteLength;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
new file mode 100644
index 0000000..60b9353
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of the inputs of a workflow run, as they are currently known
+ * about.
+ * 
+ * @author Donal Fellows.
+ */
+@XmlRootElement
+public class InputDescription extends AbstractPortDescription {
+	@XmlElement
+	public List<InputPort> input = new ArrayList<>();
+
+	@XmlType(name = "InputPort")
+	public static class InputPort extends AbstractPort {
+		@XmlAttribute(namespace = XLINK)
+		@XmlSchemaType(name = "anyURI")
+		public URI href;
+	}
+
+	/**
+	 * Add an input port to the list of ports.
+	 * 
+	 * @param name
+	 *            The name of the port to add.
+	 * @return The port (so that its details may be set);
+	 */
+	public InputPort addPort(String name) {
+		InputPort p = new InputPort();
+		p.name = name;
+		input.add(p);
+		return p;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
new file mode 100644
index 0000000..052c0ef
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "LeafValue")
+public class LeafValue extends AbstractValue {
+	@XmlAttribute(name = "contentFile")
+	public String fileName;
+	@XmlAttribute(name = "contentType")
+	public String contentType;
+	@XmlAttribute(name = "contentByteLength")
+	public Long byteLength;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
new file mode 100644
index 0000000..b14cdf1
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.taverna.server.port_description.utils.IntAdapter;
+
+@XmlType(name = "ListValue")
+public class ListValue extends AbstractValue {
+	@XmlAttribute
+	@XmlSchemaType(name = "int")
+	@XmlJavaTypeAdapter(IntAdapter.class)
+	public Integer length;
+	@XmlElements({
+			@XmlElement(name = "value", type = LeafValue.class, nillable = false),
+			@XmlElement(name = "list", type = ListValue.class, nillable = false),
+			@XmlElement(name = "error", type = ErrorValue.class, nillable = false),
+			@XmlElement(name = "absent", type = AbsentValue.class, nillable = false) })
+	public List<AbstractValue> contents = new ArrayList<>();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
new file mode 100644
index 0000000..4003cdb
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+public interface Namespaces {
+	static final String DATA = "http://ns.taverna.org.uk/2010/port/";
+	static final String RUN = "http://ns.taverna.org.uk/2010/run/";
+	static final String XLINK = "http://www.w3.org/1999/xlink";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
new file mode 100644
index 0000000..0b94973
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of the outputs of a workflow run, as they are currently known
+ * about.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "workflowOutputs")
+public class OutputDescription extends AbstractPortDescription {
+	private static final AbsentValue ABSENT_VALUE = new AbsentValue();
+	@XmlElement(name = "output")
+	public List<OutputPort> ports = new ArrayList<>();
+
+	@XmlType(name = "OutputPort")
+	public static class OutputPort extends AbstractPort {
+		@XmlElements({
+				@XmlElement(name = "value", type = LeafValue.class, nillable = false, required = true),
+				@XmlElement(name = "list", type = ListValue.class, nillable = false, required = true),
+				@XmlElement(name = "error", type = ErrorValue.class, nillable = false, required = true),
+				@XmlElement(name = "absent", type = AbsentValue.class, nillable = false, required = true) })
+		public AbstractValue output;
+	}
+
+	/**
+	 * Add an output port to the list of ports.
+	 * 
+	 * @param name
+	 *            The name of the port to add.
+	 * @return The port (so that its value may be set);
+	 */
+	public OutputPort addPort(String name) {
+		OutputPort p = new OutputPort();
+		p.name = name;
+		p.output = ABSENT_VALUE;
+		ports.add(p);
+		return p;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
new file mode 100644
index 0000000..b1ac2c6
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+@XmlSchema(namespace = DATA, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "run", namespaceURI = RUN) })
+package org.taverna.server.port_description;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.port_description.Namespaces.DATA;
+import static org.taverna.server.port_description.Namespaces.RUN;
+import static org.taverna.server.port_description.Namespaces.XLINK;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
new file mode 100644
index 0000000..8764176
--- /dev/null
+++ b/taverna-server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.port_description.utils;
+
+import static javax.xml.bind.DatatypeConverter.parseInt;
+import static javax.xml.bind.DatatypeConverter.printInt;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * A type conversion utility for use with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+public class IntAdapter extends XmlAdapter<String, Integer> {
+	@Override
+	public String marshal(Integer value) throws Exception {
+		if (value == null)
+			return null;
+		return printInt(value);
+	}
+
+	@Override
+	public Integer unmarshal(String value) throws Exception {
+		if (value == null)
+			return null;
+		return parseInt(value);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
new file mode 100644
index 0000000..c952ec2
--- /dev/null
+++ b/taverna-server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
@@ -0,0 +1,98 @@
+package org.taverna.server.port_description;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test file ensures that the JAXB bindings will work once deployed instead
+ * of mysteriously failing in service.
+ * 
+ * @author Donal Fellows
+ */
+public class JaxbSanityTest {
+	SchemaOutputResolver sink;
+	StringWriter schema;
+
+	String schema() {
+		return schema.toString();
+	}
+
+	private String schemaTest(Class<?>... classes) throws IOException, JAXBException {
+		Assert.assertTrue(schema().isEmpty());
+		JAXBContext.newInstance(classes).generateSchema(sink);
+		Assert.assertFalse(schema().isEmpty());
+		return schema();
+	}
+
+	@Before
+	public void init() {
+		schema = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(schema);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+	}
+
+	@Test
+	public void testJAXBForInput() throws Exception {
+		schemaTest(InputDescription.InputPort.class);
+	}
+
+	@Test
+	public void testJAXBForInputDescription() throws Exception {
+		schemaTest(InputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForAbsentValue() throws Exception {
+		schemaTest(AbstractValue.class);
+	}
+
+	@Test
+	public void testJAXBForAbstractValue() throws Exception {
+		schemaTest(AbstractValue.class);
+	}
+
+	@Test
+	public void testJAXBForErrorValue() throws Exception {
+		schemaTest(ErrorValue.class);
+	}
+
+	@Test
+	public void testJAXBForLeafValue() throws Exception {
+		schemaTest(LeafValue.class);
+	}
+
+	@Test
+	public void testJAXBForListValue() throws Exception {
+		schemaTest(ListValue.class);
+	}
+
+	@Test
+	public void testJAXBForOutputDescription() throws Exception {
+		schemaTest(OutputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingAtOnce() throws Exception {
+		schemaTest(AbsentValue.class, AbstractValue.class, ListValue.class,
+				LeafValue.class, ErrorValue.class, OutputDescription.class,
+				InputDescription.InputPort.class, InputDescription.class);
+		// System.out.println(schema());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/pom.xml b/taverna-server-rmidaemon/pom.xml
new file mode 100644
index 0000000..0e2a565
--- /dev/null
+++ b/taverna-server-rmidaemon/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>taverna-server-rmidaemon</artifactId>
+	<name>Apache Taverna Server RMI registry daemon</name>
+	<description>Customised RMI registry that supports restricting to localhost.</description>
+
+	<properties>
+		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
+		<mainClass>org.taverna.server.rmidaemon.Registry</mainClass>
+	</properties>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>${mainClass}</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
new file mode 100644
index 0000000..4be7579
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
@@ -0,0 +1,72 @@
+package org.taverna.server.rmidaemon;
+
+import static java.lang.System.setProperty;
+import static java.net.InetAddress.getLocalHost;
+import static java.rmi.registry.LocateRegistry.createRegistry;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.rmi.server.RMISocketFactory.getDefaultSocketFactory;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.rmi.MarshalledObject;
+import java.rmi.server.RMIServerSocketFactory;
+
+/**
+ * Special version of <tt>rmiregistry</tt>.
+ * 
+ * @author Donal Fellows
+ */
+public class Registry {
+	/**
+	 * Run a registry. The first optional argument is the port for the registry
+	 * to listen on, and the second optional argument is whether the registry
+	 * should restrict itself to connections from localhost only.
+	 * 
+	 * @param args
+	 *            Arguments to the program.
+	 */
+	public static void main(String... args) {
+		try {
+			if (args.length > 0)
+				port = Integer.parseInt(args[0]);
+		} catch (Exception e) {
+			System.err.println("failed to parse port: " + e.getMessage());
+			System.exit(2);
+		}
+		try {
+			if (args.length > 1)
+				localhostOnly = Boolean.parseBoolean(args[1]);
+		} catch (Exception e) {
+			System.err.println("failed to parse boolean localhost flag: "
+					+ e.getMessage());
+			System.exit(2);
+		}
+		try {
+			Object registryHandle = makeRegistry();
+			try (ObjectOutputStream oos = new ObjectOutputStream(System.out)) {
+				oos.writeObject(registryHandle);
+			}
+		} catch (Exception e) {
+			System.err.println("problem creating registry: " + e.getMessage());
+			System.exit(1);
+		}
+	}
+
+	private static int port = REGISTRY_PORT;
+	private static boolean localhostOnly = false;
+
+	private static MarshalledObject<java.rmi.registry.Registry> makeRegistry() throws IOException {
+		if (!localhostOnly)
+			return new MarshalledObject<>(createRegistry(port));
+		setProperty("java.rmi.server.hostname", "127.0.0.1");
+		return new MarshalledObject<>(createRegistry(port,
+				getDefaultSocketFactory(), new RMIServerSocketFactory() {
+					@Override
+					public ServerSocket createServerSocket(int port)
+							throws IOException {
+						return new ServerSocket(port, 0, getLocalHost());
+					}
+				}));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
new file mode 100644
index 0000000..32144b5
--- /dev/null
+++ b/taverna-server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * RMI daemon implementation. A variation of an RMI registry.
+ * @author Donal Fellows
+ */
+package org.taverna.server.rmidaemon;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/.gitignore b/taverna-server-runinterface/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-runinterface/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/pom.xml b/taverna-server-runinterface/pom.xml
new file mode 100644
index 0000000..efd3763
--- /dev/null
+++ b/taverna-server-runinterface/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>taverna-server-runinterface</artifactId>
+	<name>Apache Taverna Server RMI Interface: Webapp &lt;-&gt; Worker</name>
+	<description>This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
new file mode 100644
index 0000000..9f4bf50
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that indicates where a change of a workflow run's status is
+ * illegal.
+ * 
+ * @author Donal Fellows
+ * @see RemoteSingleRun#setStatus(RemoteStatus)
+ */
+@WebFault(name = "IllegalStateTransitionFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
+public class IllegalStateTransitionException extends Exception {
+	private static final long serialVersionUID = 159673249162345L;
+
+	public IllegalStateTransitionException() {
+		this("illegal state transition");
+	}
+
+	public IllegalStateTransitionException(String message) {
+		super(message);
+	}
+
+	public IllegalStateTransitionException(Throwable cause) {
+		this("illegal state transition", cause);
+	}
+
+	public IllegalStateTransitionException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
new file mode 100644
index 0000000..a47d112
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that indicates that the implementation has gone wrong in some
+ * unexpected way.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "ImplementationFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
+@SuppressWarnings("serial")
+public class ImplementationException extends Exception {
+	public ImplementationException(String message) {
+		super(message);
+	}
+
+	public ImplementationException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
new file mode 100644
index 0000000..395842a
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Represents a directory that is the working directory of a workflow run, or a
+ * sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see RemoteFile
+ */
+public interface RemoteDirectory extends RemoteDirectoryEntry {
+	/**
+	 * @return A list of the contents of the directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If anything goes wrong with listing the directory.
+	 */
+	@Nonnull
+	public Collection<RemoteDirectoryEntry> getContents()
+			throws RemoteException, IOException;
+
+	/**
+	 * Creates a sub-directory of this directory.
+	 * 
+	 * @param name
+	 *            The name of the sub-directory.
+	 * @return A handle to the newly-created directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong with creating the subdirectory.
+	 */
+	@Nonnull
+	public RemoteDirectory makeSubdirectory(@Nonnull String name)
+			throws RemoteException, IOException;
+
+	/**
+	 * Creates an empty file in this directory.
+	 * 
+	 * @param name
+	 *            The name of the file to create.
+	 * @return A handle to the newly-created file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If anything goes wrong with creating the file.
+	 */
+	@Nonnull
+	public RemoteFile makeEmptyFile(@Nonnull String name)
+			throws RemoteException, IOException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
new file mode 100644
index 0000000..1e04b44
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * An entry in a {@link RemoteDirectory} representing a file or sub-directory.
+ * 
+ * @author Donal Fellows
+ * @see RemoteDirectory
+ * @see RemoteFile
+ */
+public interface RemoteDirectoryEntry extends Remote {
+	/**
+	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
+	 *         or contain the character "<tt>/</tt>".
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getName() throws RemoteException;
+
+	/**
+	 * @return The time when the entry was last modified.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public Date getModificationDate() throws RemoteException;
+
+	/**
+	 * Gets the directory containing this directory entry.
+	 * 
+	 * @return A directory handle, or <tt>null</tt> if called on the workflow
+	 *         run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public RemoteDirectory getContainingDirectory() throws RemoteException;
+
+	/**
+	 * Destroy this directory entry, deleting the file or sub-directory. The
+	 * workflow run's working directory can never be manually destroyed.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong when deleting the directory entry.
+	 */
+	public void destroy() throws RemoteException, IOException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
new file mode 100644
index 0000000..e09466d
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.io.IOException;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Represents a file in the working directory of a workflow instance run, or in
+ * some sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see RemoteDirectory
+ */
+public interface RemoteFile extends RemoteDirectoryEntry {
+	/**
+	 * Read from the file.
+	 * 
+	 * @param offset
+	 *            Where in the file to read the bytes from.
+	 * @param length
+	 *            How much of the file to read; -1 for "to the end".
+	 * @return The literal byte contents of the given section of the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong reading the file.
+	 */
+	@Nonnull
+	byte[] getContents(int offset, int length) throws RemoteException,
+			IOException;
+
+	/**
+	 * Write the data to the file, totally replacing what was there before.
+	 * 
+	 * @param data
+	 *            The literal bytes that will form the new contents of the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong writing the contents.
+	 */
+	void setContents(@Nonnull byte[] data) throws RemoteException, IOException;
+
+	/**
+	 * Append the data to the file.
+	 * 
+	 * @param data
+	 *            The literal bytes that will be appended.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong writing the contents.
+	 */
+	void appendContents(@Nonnull byte[] data) throws RemoteException,
+			IOException;
+
+	/**
+	 * @return The length of the file, in bytes.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	long getSize() throws RemoteException;
+
+	/**
+	 * Copy from another file to this one.
+	 * 
+	 * @param sourceFile
+	 *            The other file to copy from.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws IOException
+	 *             If things go wrong during the copy.
+	 */
+	void copy(@Nonnull RemoteFile sourceFile) throws RemoteException,
+			IOException;
+
+	/**
+	 * @return The full native OS name for the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getNativeName() throws RemoteException;
+
+	/**
+	 * @return The host holding the file.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getNativeHost() throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
new file mode 100644
index 0000000..7a7510c
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * This represents the assignment of inputs to input ports of the workflow. Note
+ * that the <tt>file</tt> and <tt>value</tt> properties are never set at the
+ * same time.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteInput extends Remote {
+	/**
+	 * @return The file currently assigned to this input port, or <tt>null</tt>
+	 *         if no file is assigned.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getFile() throws RemoteException;
+
+	/**
+	 * @return The name of this input port. This may not be changed.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	String getName() throws RemoteException;
+
+	/**
+	 * @return The value currently assigned to this input port, or <tt>null</tt>
+	 *         if no value is assigned.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getValue() throws RemoteException;
+
+	/**
+	 * @return The delimiter currently used to split this input port's value
+	 *         into a list, or <tt>null</tt> if no delimiter is to be used
+	 *         (i.e., the value is a singleton).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	String getDelimiter() throws RemoteException;
+
+	/**
+	 * Sets the file to use for this input. This overrides the use of the
+	 * previous file and any set value.
+	 * 
+	 * @param file
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setFile(@Nonnull String file) throws RemoteException;
+
+	/**
+	 * Sets the value to use for this input. This overrides the use of the
+	 * previous value and any set file.
+	 * 
+	 * @param value
+	 *            The value to use.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setValue(@Nonnull String value) throws RemoteException;
+
+	/**
+	 * Sets the delimiter used to split this input port's value into a list.
+	 * 
+	 * @param delimiter
+	 *            The delimiter character, or <tt>null</tt> if no delimiter is
+	 *            to be used (i.e., the value is a singleton).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setDelimiter(@Nullable String delimiter) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
new file mode 100644
index 0000000..4001721
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An event listener that is attached to a {@link RemoteSingleRun}.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteListener extends Remote {
+	/**
+	 * @return The name of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getName() throws RemoteException;
+
+	/**
+	 * @return The type of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getType() throws RemoteException;
+
+	/**
+	 * @return The configuration document for the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getConfiguration() throws RemoteException;
+
+	/**
+	 * @return The supported properties of the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String[] listProperties() throws RemoteException;
+
+	/**
+	 * Get the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to read.
+	 * @return The value of the property.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public String getProperty(@Nonnull String propName) throws RemoteException;
+
+	/**
+	 * Set the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to write.
+	 * @param value
+	 *            The value to set the property to.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setProperty(@Nonnull String propName, @Nonnull String value)
+			throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
new file mode 100644
index 0000000..eec4ab5
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.UUID;
+
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * The main RMI-enabled interface for creating runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteRunFactory extends Remote {
+	/**
+	 * Makes a workflow run that will process a particular workflow document.
+	 * 
+	 * @param workflow
+	 *            The (serialised) workflow to instantiate as a run.
+	 * @param creator
+	 *            Who is this run created for?
+	 * @param usageRecordReceiver
+	 *            Where to write any usage records. May be <tt>null</tt> to
+	 *            cause them to not be written.
+	 * @param masterID
+	 *            The UUID of the run to use, or <tt>null</tt> if the execution
+	 *            engine is to manufacture a new one for itself.
+	 * @return A remote handle for the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	RemoteSingleRun make(@Nonnull byte[] workflow, @Nonnull String creator,
+			@Nullable UsageRecordReceiver usageRecordReceiver,
+			@Nullable UUID masterID) throws RemoteException;
+
+	/**
+	 * Asks this factory to unregister itself from the registry and cease
+	 * operation.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void shutdown() throws RemoteException;
+
+	/**
+	 * Configures the details to use when setting up the workflow run's
+	 * connnection to the interaction feed.
+	 * 
+	 * @param host
+	 *            The host where the feed is located.
+	 * @param port
+	 *            The port where the feed is located.
+	 * @param webdavPath
+	 *            The path used for pushing web pages into the feed.
+	 * @param feedPath
+	 *            The path used for reading and writing notifications on the
+	 *            feed.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setInteractionServiceDetails(@Nonnull String host,
+			@Nonnull String port, @Nonnull String webdavPath,
+			@Nonnull String feedPath) throws RemoteException;
+
+	/**
+	 * Gets a count of the number of {@linkplain RemoteSingleRun workflow runs}
+	 * that this factor knows about that are in the
+	 * {@link RemoteStatus#Operating Operating} state.
+	 * 
+	 * @return A count of "running" workflow runs.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	int countOperatingRuns() throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
new file mode 100644
index 0000000..35e6c09
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Outline of the security context for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+public interface RemoteSecurityContext extends Remote {
+	void setKeystore(@Nonnull byte[] keystore) throws RemoteException,
+			ImplementationException;
+
+	void setPassword(@Nonnull char[] password) throws RemoteException,
+			ImplementationException;
+
+	void setTruststore(@Nonnull byte[] truststore) throws RemoteException,
+			ImplementationException;
+
+	void setUriToAliasMap(@Nonnull Map<URI, String> uriToAliasMap)
+			throws RemoteException;
+
+	void setHelioToken(@Nonnull String helioToken) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
new file mode 100644
index 0000000..fa68b81
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+import java.net.URL;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public interface RemoteSingleRun extends Remote {
+	/**
+	 * @return The name of the Baclava file to use for all inputs, or
+	 *         <tt>null</tt> if no Baclava file is set.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public String getInputBaclavaFile() throws RemoteException;
+
+	/**
+	 * Sets the Baclava file to use for all inputs. This overrides the use of
+	 * individual inputs.
+	 * 
+	 * @param filename
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setInputBaclavaFile(@Nonnull String filename)
+			throws RemoteException;
+
+	/**
+	 * @return The list of input assignments.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<RemoteInput> getInputs() throws RemoteException;
+
+	/**
+	 * Create an input assignment.
+	 * 
+	 * @param name
+	 *            The name of the port that this will be an input for.
+	 * @return The assignment reference.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteInput makeInput(@Nonnull String name) throws RemoteException;
+
+	/**
+	 * @return The file (relative to the working directory) to write the outputs
+	 *         of the run to as a Baclava document, or <tt>null</tt> if they are
+	 *         to be written to non-Baclava files in a directory called
+	 *         <tt>out</tt>.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public String getOutputBaclavaFile() throws RemoteException;
+
+	/**
+	 * Sets where the output of the run is to be written to. This will cause the
+	 * output to be generated as a Baclava document, rather than a collection of
+	 * individual non-Baclava files in the subdirectory of the working directory
+	 * called <tt>out</tt>.
+	 * 
+	 * @param filename
+	 *            Where to write the Baclava file (or <tt>null</tt> to cause the
+	 *            output to be written to individual files); overwrites any
+	 *            previous setting of this value.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	public void setOutputBaclavaFile(@Nullable String filename)
+			throws RemoteException;
+
+	/**
+	 * @return The current status of the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteStatus getStatus() throws RemoteException;
+
+	/**
+	 * Set the status of the run, which should cause it to move into the given
+	 * state. This may cause some significant changes.
+	 * 
+	 * @param s
+	 *            The state to try to change to.
+	 * @throws IllegalStateTransitionException
+	 *             If the requested state change is impossible. (Note that it is
+	 *             always legal to set the status to the current status.)
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes horribly wrong on the back end.
+	 * @throws StillWorkingOnItException
+	 *             If the startup time of the workflow implementation exceeds a
+	 *             built-in threshold.
+	 */
+	public void setStatus(@Nonnull RemoteStatus s)
+			throws IllegalStateTransitionException, RemoteException,
+			ImplementationException, StillWorkingOnItException;
+
+	/**
+	 * @return When this workflow run was found to have finished, or
+	 *         <tt>null</tt> if it has never finished (either still running or
+	 *         never started).
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public Date getFinishTimestamp() throws RemoteException;
+
+	/**
+	 * @return When this workflow run was started, or <tt>null</tt> if it has
+	 *         never been started.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nullable
+	public Date getStartTimestamp() throws RemoteException;
+
+	/**
+	 * @return Handle to the main working directory of the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteDirectory getWorkingDirectory() throws RemoteException;
+
+	/**
+	 * @return The list of listener instances attached to the run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<RemoteListener> getListeners() throws RemoteException;
+
+	/**
+	 * Add a listener to the run.
+	 * 
+	 * @param listener
+	 *            The listener to add.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes wrong when adding the listener.
+	 */
+	public void addListener(@Nonnull RemoteListener listener)
+			throws RemoteException, ImplementationException;
+
+	/**
+	 * @return The security context structure for this run.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes wrong when getting the context.
+	 */
+	@Nonnull
+	public RemoteSecurityContext getSecurityContext() throws RemoteException,
+			ImplementationException;
+
+	/**
+	 * Kill off this run, removing all resources which it consumes.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 * @throws ImplementationException
+	 *             If something goes horribly wrong when destroying the run.
+	 */
+	public void destroy() throws RemoteException, ImplementationException;
+
+	/**
+	 * Get the types of listener supported by this run.
+	 * 
+	 * @return A list of listener type names.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public List<String> getListenerTypes() throws RemoteException;
+
+	/**
+	 * Create a listener that can be attached to this run.
+	 * 
+	 * @param type
+	 *            The type name of the listener to create; it must be one of the
+	 *            names returned by the {@link #getListenerTypes()} operation.
+	 * @param configuration
+	 *            The configuration document for this listener. The nature of
+	 *            the contents of this are determined by the type.
+	 * @return A handle for the listener.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	@Nonnull
+	public RemoteListener makeListener(@Nonnull String type,
+			@Nonnull String configuration) throws RemoteException;
+
+	/**
+	 * Configures the details to use when setting up the workflow run's
+	 * connnection to the interaction feed.
+	 * 
+	 * @param interactionFeed
+	 *            The location of the interaction feed. If <tt>null</tt>,
+	 *            defaults from the factory will be used instead.
+	 * @param webdavPath
+	 *            The location used for pushing web pages to support the feed.
+	 *            If <tt>null</tt>, a default from the factory will be used
+	 *            instead.
+	 * @param publishUrlBase
+	 *            Where to <i>actually</i> publish to, if this needs to be
+	 *            different from the location presented in the published HTML
+	 *            and Feed entries. Necessary in complex network scenarios.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setInteractionServiceDetails(@Nonnull URL interactionFeed,
+			@Nonnull URL webdavPath, @Nullable URL publishUrlBase) throws RemoteException;
+
+	/**
+	 * A do-nothing method, used to check the general reachability of the
+	 * workflow run.
+	 * 
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void ping() throws RemoteException;
+
+	/**
+	 * Sets whether we should generate provenance information from a run.
+	 * 
+	 * @param generateProvenance
+	 *            Boolean flag, true for do the generation. Must be set before
+	 *            starting the run for this to have an effect.
+	 * @throws RemoteException
+	 *             If anything goes wrong with the communication.
+	 */
+	void setGenerateProvenance(boolean generateProvenance)
+			throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
new file mode 100644
index 0000000..db039f0
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+/**
+ * States of a workflow run. They are {@link RemoteStatus#Initialized
+ * Initialized}, {@link RemoteStatus#Operating Operating},
+ * {@link RemoteStatus#Stopped Stopped}, and {@link RemoteStatus#Finished
+ * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the
+ * workflow run does not exist (and hence can't have its state queried or set)
+ * in that case.
+ * 
+ * @author Donal Fellows
+ */
+public enum RemoteStatus {
+	/**
+	 * The workflow run has been created, but is not yet running. The run will
+	 * need to be manually moved to {@link #Operating} when ready.
+	 */
+	Initialized,
+	/**
+	 * The workflow run is going, reading input, generating output, etc. Will
+	 * eventually either move automatically to {@link #Finished} or can be moved
+	 * manually to {@link #Stopped} (where supported).
+	 */
+	Operating,
+	/**
+	 * The workflow run is paused, and will need to be moved back to
+	 * {@link #Operating} manually.
+	 */
+	Stopped,
+	/**
+	 * The workflow run has ceased; data files will continue to exist until the
+	 * run is destroyed (which may be manual or automatic).
+	 */
+	Finished
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
new file mode 100644
index 0000000..4643d5c
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.remote;
+
+/**
+ * Exception that indicates that the implementation is still working on
+ * processing the operation. Note that though this is an exception, it is <i>not
+ * a failure</i>.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class StillWorkingOnItException extends Exception {
+	public StillWorkingOnItException(String string) {
+		super(string);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
new file mode 100644
index 0000000..9880a3b
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Interfaces exported by worker classes to the server.
+ */
+package org.taverna.server.localworker.remote;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
new file mode 100644
index 0000000..89c29ae
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Interface exported by (part of) the webapp to allow processes it creates to
+ * push in usage records.
+ * 
+ * @author Donal Fellows
+ */
+public interface UsageRecordReceiver extends Remote {
+	/**
+	 * Called to push in a usage record. Note that it is assumed that the usage
+	 * record already contains all the information required to locate and
+	 * process the job; there is no separate handle.
+	 * 
+	 * @param usageRecord
+	 *            The serialised XML of the usage record.
+	 * @throws RemoteException
+	 *             if anything goes wrong.
+	 */
+	void acceptUsageRecord(String usageRecord) throws RemoteException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
new file mode 100644
index 0000000..cdd592b
--- /dev/null
+++ b/taverna-server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Interfaces exported by the server to worker classes.
+ */
+package org.taverna.server.localworker.server;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/pom.xml b/taverna-server-unix-forker/pom.xml
new file mode 100644
index 0000000..a2beeb4
--- /dev/null
+++ b/taverna-server-unix-forker/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-unix-forker</artifactId>
+	<name>Apache Taverna Server Impersonation Module (Unix)</name>
+	<description>Manages the starting of the worker processes as different users. Unix-specific.</description>
+
+	<properties>
+		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
+		<forkerMainClass>org.taverna.server.unixforker.Forker</forkerMainClass>
+	</properties>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>${forkerMainClass}</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
----------------------------------------------------------------------
diff --git a/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
new file mode 100644
index 0000000..f9dc632
--- /dev/null
+++ b/taverna-server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.unixforker;
+
+import static java.lang.System.err;
+import static java.lang.System.getProperty;
+import static java.lang.System.in;
+import static java.lang.System.out;
+import static java.util.Arrays.asList;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A simple class that forks off processes when asked to over its standard
+ * input. The one complication is that it forks them off as other users, through
+ * the use of the <tt>sudo</tt> utility. It is Unix-specific.
+ * 
+ * @author Donal Fellows
+ */
+public class Forker extends Thread {
+	private static String password;
+	private static BufferedReader br;
+
+	/**
+	 * Helper to make reading a password from a file clearer. The password must
+	 * be the first line of the file.
+	 * 
+	 * @param passwordFile
+	 *            The file to load from.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	private static void loadPassword(@Nonnull File passwordFile)
+			throws IOException {
+		try {
+			err.println("attempting to load password from " + passwordFile);
+			try (FileReader fr = new FileReader(passwordFile)) {
+				password = new BufferedReader(fr).readLine();
+			}
+		} catch (IOException e) {
+			err.println("failed to read password from file " + passwordFile
+					+ "described in password.file property");
+			throw e;
+		}
+	}
+
+	/**
+	 * Initialization code, which runs before the main loop starts processing.
+	 * 
+	 * @param args
+	 *            The arguments to the program.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public static void init(String[] args) throws Exception {
+		if (args.length < 1)
+			throw new IllegalArgumentException(
+					"wrong # args: must be \"program ?argument ...?\"");
+		if (getProperty("password.file") != null)
+			loadPassword(new File(getProperty("password.file")));
+		if (password == null)
+			err.println("no password.file property or empty file; "
+					+ "assuming password-less sudo is configured");
+		else
+			err.println("password is of length " + password.length());
+		br = new BufferedReader(new InputStreamReader(in));
+	}
+
+	/**
+	 * The body of the main loop of this program.
+	 * 
+	 * @param args
+	 *            The arguments to use when running the other program.
+	 * @return Whether to repeat the loop.
+	 * @throws Exception
+	 *             If anything goes wrong. Note that the loop is repeated if an
+	 *             exception occurs in it.
+	 */
+	public static boolean mainLoopBody(String[] args) throws Exception {
+		String line = br.readLine();
+		if (line == null)
+			return false;
+		List<String> vals = asList(line.split("[ \t]+"));
+		if (vals.size() != 2) {
+			out.println("wrong # values: must be \"username UUID\"");
+			return true;
+		}
+		ProcessBuilder pb = new ProcessBuilder();
+		pb.command()
+				.addAll(asList("sudo", "-u", vals.get(0), "-S", "-H", "--"));
+		pb.command().addAll(asList(args));
+		pb.command().add(vals.get(1));
+		Forker f = new Forker(pb);
+		f.setDaemon(true);
+		f.start();
+		return true;
+	}
+
+	/**
+	 * The main code for this class, which turns this into an executable
+	 * program. Runs the initialisation and then the main loop, in both cases
+	 * with appropriate error handling.
+	 * 
+	 * @param args
+	 *            Arguments to this program.
+	 */
+	public static void main(String... args) {
+		try {
+			init(args);
+			while (true) {
+				try {
+					if (!mainLoopBody(args))
+						break;
+				} catch (Exception e) {
+					e.printStackTrace(err);
+					out.println(e.getClass().getName() + ": " + e.getMessage());
+				}
+			}
+			System.exit(0);
+		} catch (Exception e) {
+			e.printStackTrace(err);
+			System.exit(1);
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	public Forker(ProcessBuilder pb) throws IOException {
+		out.println("Starting subprocess: " + pb.command());
+		final Process p = pb.start();
+		abstract class ProcessAttachedDaemon extends Thread {
+			public ProcessAttachedDaemon() {
+				setDaemon(true);
+				start();
+			}
+
+			abstract void act() throws Exception;
+
+			@Override
+			public final void run() {
+				try {
+					act();
+					p.waitFor();
+				} catch (InterruptedException e) {
+					// Just drop
+				} catch (Exception e) {
+					p.destroy();
+					e.printStackTrace(err);
+				}
+			}
+		}
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				copyFromSudo("Subprocess(out):", p.getInputStream());
+			}
+		};
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				copyFromSudo("Subprocess(err):", p.getErrorStream());
+			}
+		};
+		new ProcessAttachedDaemon() {
+			@Override
+			void act() throws Exception {
+				interactWithSudo(p.getOutputStream());
+			}
+		};
+	}
+
+	protected void interactWithSudo(OutputStream os) throws Exception {
+		if (password != null) {
+			OutputStreamWriter osw = new OutputStreamWriter(os);
+			osw.write(password + "\n");
+			osw.flush();
+		}
+		os.close();
+	}
+
+	protected void copyFromSudo(String header, InputStream sudoStream)
+			throws Exception {
+		int b = '\n';
+		while (true) {
+			if (b == '\n')
+				out.print(header);
+			b = sudoStream.read();
+			if (b == -1)
+				break;
+			out.write(b);
+			out.flush();
+		}
+		sudoStream.close();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/.gitignore b/taverna-server-usagerecord/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-usagerecord/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/pom.xml b/taverna-server-usagerecord/pom.xml
new file mode 100644
index 0000000..47ab732
--- /dev/null
+++ b/taverna-server-usagerecord/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-usagerecord</artifactId>
+	<name>Apache Taverna Server Usage Record Support</name>
+	<description>Basic Java bindings for the OGF Usage Record Format, version 1.0, plus a simple wrapper to make working with it easier.</description>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>jaxb2-maven-plugin</artifactId>
+				<version>1.3.1</version>
+				<executions>
+					<execution>
+						<id>xsd2java</id>
+						<goals>
+							<goal>xjc</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/generated-sources/xjc</outputDirectory>
+							<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.codehaus.mojo</groupId>
+										<artifactId>jaxb2-maven-plugin</artifactId>
+										<versionRange>[1.3.1,)</versionRange>
+										<goals>
+											<goal>xjc</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>


[40/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java b/server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
deleted file mode 100644
index 06202dc..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
+++ /dev/null
@@ -1,278 +0,0 @@
-package org.taverna.server.master.identity;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.authentication.AccountExpiredException;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.CredentialsExpiredException;
-import org.springframework.security.authentication.DisabledException;
-import org.springframework.security.authentication.LockedException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-
-/**
- * A stripped down version of a
- * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider
- * DaoAuthenticationProvider}/
- * {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
- * AbstractUserDetailsAuthenticationProvider} that avoids much of the overhead
- * associated with that class.
- */
-public class StrippedDownAuthProvider implements AuthenticationProvider {
-	/**
-	 * The plaintext password used to perform
-	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
-	 * the user is not found to avoid SEC-2056.
-	 */
-	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
-
-	/**
-	 * The password used to perform
-	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
-	 * the user is not found to avoid SEC-2056. This is necessary, because some
-	 * {@link PasswordEncoder} implementations will short circuit if the
-	 * password is not in a valid format.
-	 */
-	private String userNotFoundEncodedPassword;
-	private UserDetailsService userDetailsService;
-	private PasswordEncoder passwordEncoder;
-	private Map<String, AuthCacheEntry> authCache = new HashMap<>();
-	protected final Log logger = LogFactory.getLog(getClass());
-
-	private static class AuthCacheEntry {
-		private String creds;
-		private long timestamp;
-		private static final long VALIDITY = 1000 * 60 * 20;
-		AuthCacheEntry(String credentials) {
-			creds = credentials;
-			timestamp = System.currentTimeMillis();
-		}
-		boolean valid(String password) {
-			return creds.equals(password) && timestamp+VALIDITY > System.currentTimeMillis();
-		}
-	}
-
-	@PerfLogged
-	@Override
-	public Authentication authenticate(Authentication authentication)
-			throws AuthenticationException {
-
-		if (!(authentication instanceof UsernamePasswordAuthenticationToken))
-			throw new IllegalArgumentException(
-					"can only authenticate against username+password");
-		UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
-
-		// Determine username
-		String username = (auth.getPrincipal() == null) ? "NONE_PROVIDED"
-				: auth.getName();
-
-		UserDetails user;
-
-		try {
-			user = retrieveUser(username, auth);
-			if (user == null)
-				throw new IllegalStateException(
-						"retrieveUser returned null - a violation of the interface contract");
-		} catch (UsernameNotFoundException notFound) {
-			if (logger.isDebugEnabled())
-				logger.debug("User '" + username + "' not found", notFound);
-			throw new BadCredentialsException("Bad credentials");
-		}
-
-		// Pre-auth
-		if (!user.isAccountNonLocked())
-			throw new LockedException("User account is locked");
-		if (!user.isEnabled())
-			throw new DisabledException("User account is disabled");
-		if (!user.isAccountNonExpired())
-			throw new AccountExpiredException("User account has expired");
-		Object credentials = auth.getCredentials();
-		if (credentials == null) {
-			logger.debug("Authentication failed: no credentials provided");
-
-			throw new BadCredentialsException("Bad credentials");
-		}
-
-		String providedPassword = credentials.toString();
-		boolean matched = false;
-		synchronized (authCache) {
-			AuthCacheEntry pw = authCache.get(username);
-			if (pw != null && providedPassword != null) {
-				if (pw.valid(providedPassword))
-					matched = true;
-				else
-					authCache.remove(username);
-			}
-		}
-		// Auth
-		if (!matched) {
-			if (!passwordEncoder.matches(providedPassword, user.getPassword())) {
-				logger.debug("Authentication failed: password does not match stored value");
-
-				throw new BadCredentialsException("Bad credentials");
-			}
-			if (providedPassword != null)
-				synchronized (authCache) {
-					authCache.put(username, new AuthCacheEntry(providedPassword));
-				}
-		}
-
-		// Post-auth
-		if (!user.isCredentialsNonExpired())
-			throw new CredentialsExpiredException(
-					"User credentials have expired");
-
-		return createSuccessAuthentication(user, auth, user);
-	}
-
-	@PreDestroy
-	void clearCache() {
-		authCache.clear();
-	}
-
-	/**
-	 * Creates a successful {@link Authentication} object.
-	 * <p>
-	 * Protected so subclasses can override.
-	 * </p>
-	 * <p>
-	 * Subclasses will usually store the original credentials the user supplied
-	 * (not salted or encoded passwords) in the returned
-	 * <code>Authentication</code> object.
-	 * </p>
-	 * 
-	 * @param principal
-	 *            that should be the principal in the returned object (defined
-	 *            by the {@link #isForcePrincipalAsString()} method)
-	 * @param authentication
-	 *            that was presented to the provider for validation
-	 * @param user
-	 *            that was loaded by the implementation
-	 * 
-	 * @return the successful authentication token
-	 */
-	private Authentication createSuccessAuthentication(Object principal,
-			Authentication authentication, UserDetails user) {
-		/*
-		 * Ensure we return the original credentials the user supplied, so
-		 * subsequent attempts are successful even with encoded passwords. Also
-		 * ensure we return the original getDetails(), so that future
-		 * authentication events after cache expiry contain the details
-		 */
-		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
-				principal, authentication.getCredentials(),
-				user.getAuthorities());
-		result.setDetails(authentication.getDetails());
-
-		return result;
-	}
-
-	@Override
-	public boolean supports(Class<?> authentication) {
-		return UsernamePasswordAuthenticationToken.class
-				.isAssignableFrom(authentication);
-	}
-
-	/**
-	 * Allows subclasses to actually retrieve the <code>UserDetails</code> from
-	 * an implementation-specific location, with the option of throwing an
-	 * <code>AuthenticationException</code> immediately if the presented
-	 * credentials are incorrect (this is especially useful if it is necessary
-	 * to bind to a resource as the user in order to obtain or generate a
-	 * <code>UserDetails</code>).
-	 * <p>
-	 * Subclasses are not required to perform any caching, as the
-	 * <code>AbstractUserDetailsAuthenticationProvider</code> will by default
-	 * cache the <code>UserDetails</code>. The caching of
-	 * <code>UserDetails</code> does present additional complexity as this means
-	 * subsequent requests that rely on the cache will need to still have their
-	 * credentials validated, even if the correctness of credentials was assured
-	 * by subclasses adopting a binding-based strategy in this method.
-	 * Accordingly it is important that subclasses either disable caching (if
-	 * they want to ensure that this method is the only method that is capable
-	 * of authenticating a request, as no <code>UserDetails</code> will ever be
-	 * cached) or ensure subclasses implement
-	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
-	 * to compare the credentials of a cached <code>UserDetails</code> with
-	 * subsequent authentication requests.
-	 * </p>
-	 * <p>
-	 * Most of the time subclasses will not perform credentials inspection in
-	 * this method, instead performing it in
-	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
-	 * so that code related to credentials validation need not be duplicated
-	 * across two methods.
-	 * </p>
-	 * 
-	 * @param username
-	 *            The username to retrieve
-	 * @param authentication
-	 *            The authentication request, which subclasses <em>may</em> need
-	 *            to perform a binding-based retrieval of the
-	 *            <code>UserDetails</code>
-	 * 
-	 * @return the user information (never <code>null</code> - instead an
-	 *         exception should the thrown)
-	 * 
-	 * @throws AuthenticationException
-	 *             if the credentials could not be validated (generally a
-	 *             <code>BadCredentialsException</code>, an
-	 *             <code>AuthenticationServiceException</code> or
-	 *             <code>UsernameNotFoundException</code>)
-	 */
-	private UserDetails retrieveUser(String username,
-			UsernamePasswordAuthenticationToken authentication)
-			throws AuthenticationException {
-		try {
-			return userDetailsService.loadUserByUsername(username);
-		} catch (UsernameNotFoundException notFound) {
-			if (authentication.getCredentials() != null) {
-				String presentedPassword = authentication.getCredentials()
-						.toString();
-				passwordEncoder.matches(presentedPassword,
-						userNotFoundEncodedPassword);
-			}
-			throw notFound;
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception repositoryProblem) {
-			throw new AuthenticationServiceException(
-					repositoryProblem.getMessage(), repositoryProblem);
-		}
-	}
-
-	/**
-	 * Sets the PasswordEncoder instance to be used to encode and validate
-	 * passwords.
-	 */
-	@Required
-	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
-		if (passwordEncoder == null)
-			throw new IllegalArgumentException("passwordEncoder cannot be null");
-
-		this.passwordEncoder = passwordEncoder;
-		this.userNotFoundEncodedPassword = passwordEncoder
-				.encode(USER_NOT_FOUND_PASSWORD);
-	}
-
-	@Required
-	public void setUserDetailsService(UserDetailsService userDetailsService) {
-		if (userDetailsService == null)
-			throw new IllegalStateException("A UserDetailsService must be set");
-		this.userDetailsService = userDetailsService;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/User.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/User.java b/server-webapp/src/main/java/org/taverna/server/master/identity/User.java
deleted file mode 100644
index bdb6e40..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/User.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.Query;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * The representation of a user in the database.
- * <p>
- * A user consists logically of a (non-ordered) tuple of items:
- * <ul>
- * <li>The {@linkplain #getUsername() user name},
- * <li>The {@linkplain #getPassword() user's password} (salted, encoded),
- * <li>Whether the user is {@linkplain #isEnabled() enabled} (i.e., able to log
- * in),
- * <li>Whether the user has {@linkplain #isAdmin() administrative privileges}, and
- * <li>What {@linkplain #getLocalUsername() system (Unix) account} the user's
- * workflows will run as; separation between different users that are mapped to
- * the same system account is nothing like as strongly enforced.
- * </ul>
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(schema = "USERS", table = "LIST")
-@Query(name = "users", language = "SQL", value = "SELECT id FROM USERS.LIST ORDER BY id", resultClass = String.class)
-@XmlRootElement
-@XmlType(name = "User", propOrder = {})
-@SuppressWarnings("serial")
-public class User implements UserDetails {
-	@XmlElement
-	@Persistent
-	private boolean disabled;
-	@XmlElement(name = "username", required = true)
-	@Persistent(primaryKey = "true")
-	private String id;
-	@XmlElement(name = "password", required = true)
-	@Persistent(column = "password")
-	private String encodedPassword;
-	@XmlElement
-	@Persistent
-	private boolean admin;
-	@XmlElement
-	@Persistent
-	private String localUsername;
-
-	@Override
-	public Collection<GrantedAuthority> getAuthorities() {
-		List<GrantedAuthority> auths = new ArrayList<>();
-		auths.add(new LiteralGrantedAuthority(USER));
-		if (admin)
-			auths.add(new LiteralGrantedAuthority(ADMIN));
-		if (localUsername != null)
-			auths.add(new LiteralGrantedAuthority(AUTHORITY_PREFIX
-					+ localUsername));
-		return auths;
-	}
-
-	@Override
-	public String getPassword() {
-		return encodedPassword;
-	}
-
-	@Override
-	public String getUsername() {
-		return id;
-	}
-
-	@Override
-	public boolean isAccountNonExpired() {
-		return true;
-	}
-
-	@Override
-	public boolean isAccountNonLocked() {
-		return true;
-	}
-
-	@Override
-	public boolean isCredentialsNonExpired() {
-		return true;
-	}
-
-	@Override
-	public boolean isEnabled() {
-		return !disabled;
-	}
-
-	void setDisabled(boolean disabled) {
-		this.disabled = disabled;
-	}
-
-	void setUsername(String username) {
-		this.id = username;
-	}
-
-	void setEncodedPassword(String password) {
-		this.encodedPassword = password;
-	}
-
-	void setAdmin(boolean admin) {
-		this.admin = admin;
-	}
-
-	public boolean isAdmin() {
-		return admin;
-	}
-
-	void setLocalUsername(String localUsername) {
-		this.localUsername = localUsername;
-	}
-
-	public String getLocalUsername() {
-		return localUsername;
-	}
-}
-
-@SuppressWarnings("serial")
-class LiteralGrantedAuthority implements GrantedAuthority {
-	private String auth;
-
-	LiteralGrantedAuthority(String auth) {
-		this.auth = auth;
-	}
-
-	@Override
-	public String getAuthority() {
-		return auth;
-	}
-
-	@Override
-	public String toString() {
-		return "AUTHORITY(" + auth + ")";
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java b/server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
deleted file mode 100644
index 054d932..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.dao.DataAccessException;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedOperation;
-import org.springframework.jmx.export.annotation.ManagedOperationParameter;
-import org.springframework.jmx.export.annotation.ManagedOperationParameters;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.core.userdetails.memory.UserAttribute;
-import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
-
-/**
- * The bean class that is responsible for managing the users in the database.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-@ManagedResource(objectName = JMX_ROOT + "Users", description = "The user database.")
-public class UserStore extends JDOSupport<User> implements UserDetailsService,
-		UserStoreAPI {
-	/** The logger for the user store. */
-	private transient Log log = getLog("Taverna.Server.UserDB");
-
-	public UserStore() {
-		super(User.class);
-	}
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private Map<String, BootstrapUserInfo> base = new HashMap<>();
-	private String defLocalUser;
-	private PasswordEncoder encoder;
-	private volatile int epoch;
-
-	/**
-	 * Install the encoder that will be used to turn a plaintext password into
-	 * something that it is safe to store in the database.
-	 * 
-	 * @param encoder
-	 *            The password encoder bean to install.
-	 */
-	public void setEncoder(PasswordEncoder encoder) {
-		this.encoder = encoder;
-	}
-
-	public void setBaselineUserProperties(Properties props) {
-		UserAttributeEditor parser = new UserAttributeEditor();
-
-		for (Object name : props.keySet()) {
-			String username = (String) name;
-			String value = props.getProperty(username);
-
-			// Convert value to a password, enabled setting, and list of granted
-			// authorities
-			parser.setAsText(value);
-
-			UserAttribute attr = (UserAttribute) parser.getValue();
-			if (attr != null && attr.isEnabled())
-				base.put(username, new BootstrapUserInfo(username, attr));
-		}
-	}
-
-	private void installPassword(User u, String password) {
-		u.setEncodedPassword(encoder.encode(password));
-	}
-
-	public void setDefaultLocalUser(String defLocalUser) {
-		this.defLocalUser = defLocalUser;
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> getUsers() {
-		return (List<String>) namedQuery("users").execute();
-	}
-
-	@WithinSingleTransaction
-	@PostConstruct
-	void initDB() {
-		if (base == null || base.isEmpty())
-			log.warn("no baseline user collection");
-		else if (!getUsers().isEmpty())
-			log.info("using existing users from database");
-		else
-			for (String username : base.keySet()) {
-				BootstrapUserInfo ud = base.get(username);
-				if (ud == null)
-					continue;
-				User u = ud.get(encoder);
-				if (u == null)
-					continue;
-				log.info("bootstrapping user " + username + " in the database");
-				persist(u);
-			}
-		base = null;
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedAttribute(description = "The list of server accounts known about.", currencyTimeLimit = 30)
-	public List<String> getUserNames() {
-		return getUsers();
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	public User getUser(String userName) {
-		return detach(getById(userName));
-	}
-
-	/**
-	 * Get information about a server account.
-	 * 
-	 * @param userName
-	 *            The username to look up.
-	 * @return A description map intended for use by a server admin over JMX.
-	 */
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Get information about a server account.")
-	@ManagedOperationParameters(@ManagedOperationParameter(name = "userName", description = "The username to look up."))
-	public Map<String, String> getUserInfo(String userName) {
-		User u = getById(userName);
-		Map<String, String> info = new HashMap<>();
-		info.put("name", u.getUsername());
-		info.put("admin", u.isAdmin() ? "yes" : "no");
-		info.put("enabled", u.isEnabled() ? "yes" : "no");
-		info.put("localID", u.getLocalUsername());
-		return info;
-	}
-
-	/**
-	 * Get a list of all the users in the database.
-	 * 
-	 * @return A list of user details, <i>copied</i> out of the database.
-	 */
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<UserDetails> listUsers() {
-		ArrayList<UserDetails> result = new ArrayList<>();
-		for (String id : getUsers())
-			result.add(detach(getById(id)));
-		return result;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Create a new user account; the account will be disabled and "
-			+ "non-administrative by default. Does not create any underlying system account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to create."),
-			@ManagedOperationParameter(name = "password", description = "The password to use."),
-			@ManagedOperationParameter(name = "coupleLocalUsername", description = "Whether to set the local user name to the 'main' one.") })
-	public void addUser(String username, String password,
-			boolean coupleLocalUsername) {
-		if (username.matches(".*[^a-zA-Z0-9].*"))
-			throw new IllegalArgumentException(
-					"bad user name; must be pure alphanumeric");
-		if (getById(username) != null)
-			throw new IllegalArgumentException("user name already exists");
-		User u = new User();
-		u.setDisabled(true);
-		u.setAdmin(false);
-		u.setUsername(username);
-		installPassword(u, password);
-		if (coupleLocalUsername)
-			u.setLocalUsername(username);
-		else
-			u.setLocalUsername(defLocalUser);
-		log.info("creating user for " + username);
-		persist(u);
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Set or clear whether this account is enabled. "
-			+ "Disabled accounts cannot be used to log in.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "enabled", description = "Whether to enable the account.") })
-	public void setUserEnabled(String username, boolean enabled) {
-		User u = getById(username);
-		if (u != null) {
-			u.setDisabled(!enabled);
-			log.info((enabled ? "enabling" : "disabling") + " user " + username);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Set or clear the mark on an account that indicates "
-			+ "that it has administrative privileges.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "admin", description = "Whether the account has admin privileges.") })
-	public void setUserAdmin(String username, boolean admin) {
-		User u = getById(username);
-		if (u != null) {
-			u.setAdmin(admin);
-			log.info((admin ? "enabling" : "disabling") + " user " + username
-					+ " admin status");
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Change the password for an account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "password", description = "The new password to use.") })
-	public void setUserPassword(String username, String password) {
-		User u = getById(username);
-		if (u != null) {
-			installPassword(u, password);
-			log.info("changing password for user " + username);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Change what local system account to use for a server account.")
-	@ManagedOperationParameters({
-			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
-			@ManagedOperationParameter(name = "password", description = "The new local user account use.") })
-	public void setUserLocalUser(String username, String localUsername) {
-		User u = getById(username);
-		if (u != null) {
-			u.setLocalUsername(localUsername);
-			log.info("mapping user " + username + " to local account "
-					+ localUsername);
-			epoch++;
-		}
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	@ManagedOperation(description = "Delete a server account. The underlying "
-			+ "system account is not modified.")
-	@ManagedOperationParameters(@ManagedOperationParameter(name = "username", description = "The username to delete."))
-	public void deleteUser(String username) {
-		delete(getById(username));
-		log.info("deleting user " + username);
-		epoch++;
-	}
-
-	@Override
-	@PerfLogged
-	@WithinSingleTransaction
-	public UserDetails loadUserByUsername(String username)
-			throws UsernameNotFoundException, DataAccessException {
-		User u;
-		if (base != null) {
-			log.warn("bootstrap user store still installed!");
-			BootstrapUserInfo ud = base.get(username);
-			if (ud != null) {
-				log.warn("retrieved production credentials for " + username
-						+ " from bootstrap store");
-				u = ud.get(encoder);
-				if (u != null)
-					return u;
-			}
-		}
-		try {
-			u = detach(getById(username));
-		} catch (NullPointerException npe) {
-			throw new UsernameNotFoundException("who are you?");
-		} catch (Exception ex) {
-			throw new UsernameNotFoundException("who are you?", ex);
-		}
-		if (u != null)
-			return u;
-		throw new UsernameNotFoundException("who are you?");
-	}
-
-	int getEpoch() {
-		return epoch;
-	}
-
-	public static class CachedUserStore implements UserDetailsService {
-		private int epoch;
-		private Map<String, UserDetails> cache = new HashMap<>();
-		private UserStore realStore;
-
-		@Required
-		public void setRealStore(UserStore store) {
-			this.realStore = store;
-		}
-
-		@Override
-		@PerfLogged
-		public UserDetails loadUserByUsername(String username) {
-			int epoch = realStore.getEpoch();
-			UserDetails details;
-			synchronized (cache) {
-				if (epoch != this.epoch) {
-					cache.clear();
-					this.epoch = epoch;
-					details = null;
-				} else
-					details = cache.get(username);
-			}
-			if (details == null) {
-				details = realStore.loadUserByUsername(username);
-				synchronized (cache) {
-					cache.put(username, details);
-				}
-			}
-			return details;
-		}
-	}
-
-	private static class BootstrapUserInfo {
-		private String user;
-		private String pass;
-		private Collection<GrantedAuthority> auth;
-
-		BootstrapUserInfo(String username, UserAttribute attr) {
-			user = username;
-			pass = attr.getPassword();
-			auth = attr.getAuthorities();
-		}
-
-		User get(PasswordEncoder encoder) {
-			User u = new User();
-			boolean realUser = false;
-			for (GrantedAuthority ga : auth) {
-				String a = ga.getAuthority();
-				if (a.startsWith(AUTHORITY_PREFIX))
-					u.setLocalUsername(a.substring(AUTHORITY_PREFIX.length()));
-				else if (a.equals(USER))
-					realUser = true;
-				else if (a.equals(ADMIN))
-					u.setAdmin(true);
-			}
-			if (!realUser)
-				return null;
-			u.setUsername(user);
-			u.setEncodedPassword(encoder.encode(pass));
-			u.setDisabled(false);
-			return u;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java b/server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
deleted file mode 100644
index a048da9..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.taverna.server.master.identity;
-
-import java.util.List;
-
-/**
- * The API that is exposed by the DAO that exposes user management.
- * 
- * @author Donal Fellows
- * @see User
- */
-public interface UserStoreAPI {
-	/**
-	 * List the currently-known account names.
-	 * 
-	 * @return A list of users in the database. Note that this is a snapshot.
-	 */
-	List<String> getUserNames();
-
-	/**
-	 * Get a particular user's description.
-	 * 
-	 * @param userName
-	 *            The username to look up.
-	 * @return A <i>copy</i> of the user description.
-	 */
-	User getUser(String userName);
-
-	/**
-	 * Create a new user account; the account will be disabled and
-	 * non-administrative by default. Does not create any underlying system
-	 * account.
-	 * 
-	 * @param username
-	 *            The username to create.
-	 * @param password
-	 *            The password to use.
-	 * @param coupleLocalUsername
-	 *            Whether to set the local user name to the 'main' one.
-	 */
-	void addUser(String username, String password, boolean coupleLocalUsername);
-
-	/**
-	 * Set or clear whether this account is enabled. Disabled accounts cannot be
-	 * used to log in.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param enabled
-	 *            Whether to enable the account.
-	 */
-	void setUserEnabled(String username, boolean enabled);
-
-	/**
-	 * Set or clear the mark on an account that indicates that it has
-	 * administrative privileges.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param admin
-	 *            Whether the account has admin privileges.
-	 */
-	void setUserAdmin(String username, boolean admin);
-
-	/**
-	 * Change the password for an account.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param password
-	 *            The new password to use.
-	 */
-	void setUserPassword(String username, String password);
-
-	/**
-	 * Change what local system account to use for a server account.
-	 * 
-	 * @param username
-	 *            The username to adjust.
-	 * @param localUsername
-	 *            The new local user account use.
-	 */
-	void setUserLocalUser(String username, String localUsername);
-
-	/**
-	 * Delete a server account. The underlying system account is not modified.
-	 * 
-	 * @param username
-	 *            The username to delete.
-	 */
-	void deleteUser(String username);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java b/server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
deleted file mode 100644
index 9219a60..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE.txt" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static java.util.Collections.synchronizedMap;
-import static org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes;
-import static org.taverna.server.master.common.Roles.SELF;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.web.authentication.WebAuthenticationDetails;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.RunDatabaseDAO;
-
-/**
- * A special authentication provider that allows a workflow to authenticate to
- * itself. This is used to allow the workflow to publish to its own interaction
- * feed.
- * 
- * @author Donal Fellows
- */
-public class WorkflowInternalAuthProvider extends
-		AbstractUserDetailsAuthenticationProvider {
-	private Log log = LogFactory.getLog("Taverna.Server.UserDB");
-	private static final boolean logDecisions = true;
-	public static final String PREFIX = "wfrun_";
-	private RunDatabaseDAO dao;
-	private Map<String, String> cache;
-
-	@Required
-	public void setDao(RunDatabaseDAO dao) {
-		this.dao = dao;
-	}
-
-	@Required
-	@SuppressWarnings("serial")
-	public void setCacheBound(final int bound) {
-		cache = synchronizedMap(new LinkedHashMap<String, String>() {
-			@Override
-			protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
-				return size() > bound;
-			}
-		});
-	}
-
-	public void setAuthorizedAddresses(String[] addresses) {
-		authorizedAddresses = new HashSet<>(localAddresses);
-		for (String s : addresses)
-			authorizedAddresses.add(s);
-	}
-
-	@PostConstruct
-	public void logConfig() {
-		log.info("authorized addresses for automatic access: "
-				+ authorizedAddresses);
-	}
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private final Set<String> localAddresses = new HashSet<>();
-	private Set<String> authorizedAddresses;
-	{
-		localAddresses.add("127.0.0.1"); // IPv4
-		localAddresses.add("::1"); // IPv6
-		try {
-			InetAddress addr = InetAddress.getLocalHost();
-			if (!addr.isLoopbackAddress())
-				localAddresses.add(addr.getHostAddress());
-		} catch (UnknownHostException e) {
-			// Ignore the exception
-		}
-		authorizedAddresses = new HashSet<>(localAddresses);
-	}
-
-	/**
-	 * Check that the authentication request is actually valid for the given
-	 * user record.
-	 * 
-	 * @param userRecord
-	 *            as retrieved from the
-	 *            {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)}
-	 *            or <code>UserCache</code>
-	 * @param principal
-	 *            the principal that is trying to authenticate (and that we're
-	 *            trying to bind)
-	 * @param credentials
-	 *            the credentials (e.g., password) presented by the principal
-	 * 
-	 * @throws AuthenticationException
-	 *             AuthenticationException if the credentials could not be
-	 *             validated (generally a <code>BadCredentialsException</code>,
-	 *             an <code>AuthenticationServiceException</code>)
-	 * @throws Exception
-	 *             If something goes wrong. Will be logged and converted to a
-	 *             generic AuthenticationException.
-	 */
-	protected void additionalAuthenticationChecks(UserDetails userRecord,
-			@Nonnull Object principal, @Nonnull Object credentials)
-			throws Exception {
-		@Nonnull
-		HttpServletRequest req = ((ServletRequestAttributes) currentRequestAttributes())
-				.getRequest();
-
-		// Are we coming from a "local" address?
-		if (!req.getLocalAddr().equals(req.getRemoteAddr())
-				&& !authorizedAddresses.contains(req.getRemoteAddr())) {
-			if (logDecisions)
-				log.info("attempt to use workflow magic token from untrusted address:"
-						+ " token="
-						+ userRecord.getUsername()
-						+ ", address="
-						+ req.getRemoteAddr());
-			throw new BadCredentialsException("bad login token");
-		}
-
-		// Does the password match?
-		if (!credentials.equals(userRecord.getPassword())) {
-			if (logDecisions)
-				log.info("workflow magic token is untrusted due to password mismatch:"
-						+ " wanted="
-						+ userRecord.getPassword()
-						+ ", got="
-						+ credentials);
-			throw new BadCredentialsException("bad login token");
-		}
-
-		if (logDecisions)
-			log.info("granted role " + SELF + " to user "
-					+ userRecord.getUsername());
-	}
-
-	/**
-	 * Retrieve the <code>UserDetails</code> from the relevant store, with the
-	 * option of throwing an <code>AuthenticationException</code> immediately if
-	 * the presented credentials are incorrect (this is especially useful if it
-	 * is necessary to bind to a resource as the user in order to obtain or
-	 * generate a <code>UserDetails</code>).
-	 * 
-	 * @param username
-	 *            The username to retrieve
-	 * @param details
-	 *            The details from the authentication request.
-	 * @see #retrieveUser(String,UsernamePasswordAuthenticationToken)
-	 * @return the user information (never <code>null</code> - instead an
-	 *         exception should the thrown)
-	 * @throws AuthenticationException
-	 *             if the credentials could not be validated (generally a
-	 *             <code>BadCredentialsException</code>, an
-	 *             <code>AuthenticationServiceException</code> or
-	 *             <code>UsernameNotFoundException</code>)
-	 * @throws Exception
-	 *             If something goes wrong. It will be logged and converted into
-	 *             a general AuthenticationException.
-	 */
-	@Nonnull
-	protected UserDetails retrieveUser(String username, Object details)
-			throws Exception {
-		if (details == null || !(details instanceof WebAuthenticationDetails))
-			throw new UsernameNotFoundException("context unsupported");
-		if (!username.startsWith(PREFIX))
-			throw new UsernameNotFoundException(
-					"unsupported username for this provider");
-		if (logDecisions)
-			log.info("request for auth for user " + username);
-		String wfid = username.substring(PREFIX.length());
-		String securityToken;
-		try {
-			securityToken = cache.get(wfid);
-			if (securityToken == null) {
-				securityToken = dao.getSecurityToken(wfid);
-				if (securityToken == null)
-					throw new UsernameNotFoundException("no such user");
-				cache.put(wfid, securityToken);
-			}
-		} catch (NullPointerException npe) {
-			throw new UsernameNotFoundException("no such user");
-		}
-		return new User(username, securityToken, true, true, true, true,
-				Arrays.asList(new LiteralGrantedAuthority(SELF),
-						new WorkflowSelfAuthority(wfid)));
-	}
-
-	@Override
-	@PerfLogged
-	protected final void additionalAuthenticationChecks(UserDetails userRecord,
-			UsernamePasswordAuthenticationToken token) {
-		try {
-			additionalAuthenticationChecks(userRecord, token.getPrincipal(),
-					token.getCredentials());
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception e) {
-			log.warn("unexpected failure in authentication", e);
-			throw new AuthenticationServiceException(
-					"unexpected failure in authentication", e);
-		}
-	}
-
-	@Override
-	@Nonnull
-	@PerfLogged
-	protected final UserDetails retrieveUser(String username,
-			UsernamePasswordAuthenticationToken token) {
-		try {
-			return retrieveUser(username, token.getDetails());
-		} catch (AuthenticationException e) {
-			throw e;
-		} catch (Exception e) {
-			log.warn("unexpected failure in authentication", e);
-			throw new AuthenticationServiceException(
-					"unexpected failure in authentication", e);
-		}
-	}
-
-	@SuppressWarnings("serial")
-	public static class WorkflowSelfAuthority extends LiteralGrantedAuthority {
-		public WorkflowSelfAuthority(String wfid) {
-			super(wfid);
-		}
-
-		public String getWorkflowID() {
-			return getAuthority();
-		}
-
-		@Override
-		public String toString() {
-			return "WORKFLOW(" + getAuthority() + ")";
-		}
-	}
-
-	public static class WorkflowSelfIDMapper implements LocalIdentityMapper {
-		private Log log = LogFactory.getLog("Taverna.Server.UserDB");
-		private RunStore runStore;
-
-		@PreDestroy
-		void closeLog() {
-			log = null;
-		}
-
-		@Required
-		public void setRunStore(RunStore runStore) {
-			this.runStore = runStore;
-		}
-
-		private String getUsernameForSelfAccess(WorkflowSelfAuthority authority)
-				throws UnknownRunException {
-			return runStore.getRun(authority.getWorkflowID())
-					.getSecurityContext().getOwner().getName();
-		}
-
-		@Override
-		@PerfLogged
-		public String getUsernameForPrincipal(UsernamePrincipal user) {
-			Authentication auth = SecurityContextHolder.getContext()
-					.getAuthentication();
-			if (auth == null || !auth.isAuthenticated())
-				return null;
-			try {
-				for (GrantedAuthority authority : auth.getAuthorities())
-					if (authority instanceof WorkflowSelfAuthority)
-						return getUsernameForSelfAccess((WorkflowSelfAuthority) authority);
-			} catch (UnknownRunException e) {
-				log.warn("workflow run disappeared during computation of workflow map identity");
-			}
-			return null;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
deleted file mode 100644
index dd1500a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Implementations of beans that map global user identities to local
- * usernames.
- */
-package org.taverna.server.master.identity;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java b/server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
deleted file mode 100644
index 99e1d99..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interaction;
-
-import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
-import static java.util.Collections.reverse;
-import static javax.management.Query.attr;
-import static javax.management.Query.match;
-import static javax.management.Query.value;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.factory.Factory;
-import org.apache.abdera.i18n.iri.IRI;
-import org.apache.abdera.model.Document;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.apache.abdera.parser.Parser;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
-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.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Bean that supports interaction feeds. This glues together the Abdera
- * serialization engine and the directory-based model used inside the server.
- * 
- * @author Donal Fellows
- */
-public class InteractionFeedSupport {
-	/**
-	 * The name of the resource within the run resource that is the run's
-	 * interaction feed resource.
-	 */
-	public static final String FEED_URL_DIR = "interaction";
-	/**
-	 * The name of the directory below the run working directory that will
-	 * contain the entries of the interaction feed.
-	 */
-	public static final String FEED_DIR = "feed";
-	/**
-	 * Should the contents of the entry be stripped when describing the overall
-	 * feed? This makes sense if (and only if) large entries are being pushed
-	 * through the feed.
-	 */
-	private static final boolean STRIP_CONTENTS = false;
-	/** Maximum size of an entry before truncation. */
-	private static final long MAX_ENTRY_SIZE = 50 * 1024;
-	/** Extension for entry files. */
-	private static final String EXT = ".atom";
-
-	private TavernaServerSupport support;
-	private FilenameUtils utils;
-	private Writer writer;
-	private Parser parser;
-	private Factory factory;
-	private UriBuilderFactory uriBuilder;
-
-	private AtomicInteger counter = new AtomicInteger();
-
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Required
-	public void setUtils(FilenameUtils utils) {
-		this.utils = utils;
-	}
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		this.factory = abdera.getFactory();
-		this.parser = abdera.getParser();
-		this.writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	@Required
-	// webapp
-	public void setUriBuilder(UriBuilderFactory uriBuilder) {
-		this.uriBuilder = uriBuilder;
-	}
-
-	private final Map<String, URL> endPoints = new HashMap<>();
-
-	@PostConstruct
-	void determinePorts() {
-		try {
-			MBeanServer mbs = getPlatformMBeanServer();
-			for (ObjectName obj : mbs.queryNames(new ObjectName(
-					"*:type=Connector,*"),
-					match(attr("protocol"), value("HTTP/1.1")))) {
-				String scheme = mbs.getAttribute(obj, "scheme").toString();
-				String port = obj.getKeyProperty("port");
-				endPoints.put(scheme, new URL(scheme + "://localhost:" + port));
-			}
-			getLog(getClass()).info(
-					"installed feed port publication mapping for "
-							+ endPoints.keySet());
-		} catch (Exception e) {
-			getLog(getClass()).error(
-					"failure in determining local port mapping", e);
-		}
-	}
-	
-	/**
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @return The URI of the feed
-	 */
-	public URI getFeedURI(TavernaRun run) {
-		return uriBuilder.getRunUriBuilder(run).path(FEED_URL_DIR).build();
-	}
-
-	@Nullable
-	public URL getLocalFeedBase(URI feedURI) {
-		if (feedURI == null)
-			return null;
-		return endPoints.get(feedURI.getScheme());
-	}
-
-	/**
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param id
-	 *            The ID of the entry.
-	 * @return The URI of the entry.
-	 */
-	public URI getEntryURI(TavernaRun run, String id) {
-		return uriBuilder.getRunUriBuilder(run)
-				.path(FEED_URL_DIR + "/{entryID}").build(id);
-	}
-
-	private Entry getEntryFromFile(File f) throws FilesystemAccessException {
-		long size = f.getSize();
-		if (size > MAX_ENTRY_SIZE)
-			throw new FilesystemAccessException("entry larger than 50kB");
-		byte[] contents = f.getContents(0, (int) size);
-		Document<Entry> doc = parser.parse(new ByteArrayInputStream(contents));
-		return doc.getRoot();
-	}
-
-	private void putEntryInFile(Directory dir, String name, Entry contents)
-			throws FilesystemAccessException, NoUpdateException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		try {
-			writer.writeTo(contents, baos);
-		} catch (IOException e) {
-			throw new NoUpdateException("failed to serialize the ATOM entry", e);
-		}
-		File f = dir.makeEmptyFile(support.getPrincipal(), name);
-		f.appendContents(baos.toByteArray());
-	}
-
-	private List<DirectoryEntry> listPossibleEntries(TavernaRun run)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		List<DirectoryEntry> entries = new ArrayList<>(utils.getDirectory(run,
-				FEED_DIR).getContentsByDate());
-		reverse(entries);
-		return entries;
-	}
-
-	private String getRunURL(TavernaRun run) {
-		return new IRI(uriBuilder.getRunUriBuilder(run).build()).toString();
-	}
-
-	/**
-	 * Get the interaction feed for a partciular run.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @return The Abdera feed descriptor.
-	 * @throws FilesystemAccessException
-	 *             If the feed directory can't be read for some reason.
-	 * @throws NoDirectoryEntryException
-	 *             If the feed directory doesn't exist or an entry is
-	 *             unexpectedly removed.
-	 */
-	public Feed getRunFeed(TavernaRun run) throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		URI feedURI = getFeedURI(run);
-		Feed feed = factory.newFeed();
-		feed.setTitle("Interactions for Taverna Run \"" + run.getName() + "\"");
-		feed.addLink(new IRI(feedURI).toString(), "self");
-		feed.addLink(getRunURL(run), "workflowrun");
-		boolean fetchedDate = false;
-		for (DirectoryEntry de : listPossibleEntries(run)) {
-			if (!(de instanceof File))
-				continue;
-			try {
-				Entry e = getEntryFromFile((File) de);
-				if (STRIP_CONTENTS)
-					e.setContentElement(null);
-				feed.addEntry(e);
-				if (fetchedDate)
-					continue;
-				Date last = e.getUpdated();
-				if (last == null)
-					last = e.getPublished();
-				if (last == null)
-					last = de.getModificationDate();
-				feed.setUpdated(last);
-				fetchedDate = true;
-			} catch (FilesystemAccessException e) {
-				// Can't do anything about it, so we'll just drop the entry.
-			}
-		}
-		return feed;
-	}
-
-	/**
-	 * Gets the contents of a particular feed entry.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entryID
-	 *            The identifier (from the path) of the entry to read.
-	 * @return The description of the entry.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be read or is too large.
-	 * @throws NoDirectoryEntryException
-	 *             If the entry can't be found.
-	 */
-	public Entry getRunFeedEntry(TavernaRun run, String entryID)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		File entryFile = utils.getFile(run, FEED_DIR + "/" + entryID + EXT);
-		return getEntryFromFile(entryFile);
-	}
-
-	/**
-	 * Given a partial feed entry, store a complete feed entry in the filesystem
-	 * for a particular run. Note that this does not permit update of an
-	 * existing entry; the entry is always created new.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entry
-	 *            The partial entry to store
-	 * @return A link to the entry.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be stored.
-	 * @throws NoDirectoryEntryException
-	 *             If the run is improperly configured.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to do the write.
-	 * @throws MalformedURLException
-	 *             If a generated URL is illegal (shouldn't happen).
-	 */
-	public Entry addRunFeedEntry(TavernaRun run, Entry entry)
-			throws FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		support.permitUpdate(run);
-		Date now = new Date();
-		entry.newId();
-		String localId = "entry_" + counter.incrementAndGet();
-		IRI selfLink = new IRI(getEntryURI(run, localId));
-		entry.addLink(selfLink.toString(), "self");
-		entry.addLink(getRunURL(run), "workflowrun");
-		entry.setUpdated(now);
-		entry.setPublished(now);
-		putEntryInFile(utils.getDirectory(run, FEED_DIR), localId + EXT, entry);
-		return getEntryFromFile(utils.getFile(run, FEED_DIR + "/" + localId
-				+ EXT));
-	}
-
-	/**
-	 * Deletes an entry from a feed.
-	 * 
-	 * @param run
-	 *            The workflow run that defines which feed we are operating on.
-	 * @param entryID
-	 *            The ID of the entry to delete.
-	 * @throws FilesystemAccessException
-	 *             If the entry can't be deleted
-	 * @throws NoDirectoryEntryException
-	 *             If the entry can't be found.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to modify the run's
-	 *             characteristics.
-	 */
-	public void removeRunFeedEntry(TavernaRun run, String entryID)
-			throws FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		support.permitUpdate(run);
-		utils.getFile(run, FEED_DIR + "/" + entryID + EXT).destroy();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
deleted file mode 100644
index 9efc30d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the Atom feed implementation for interactions for a particular workflow run.
- * @author Donal Fellows
- */
-package org.taverna.server.master.interaction;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
deleted file mode 100644
index 9a0a84e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.io.PipedInputStream;
-import java.security.Principal;
-import java.util.Collection;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * Represents a directory that is the working directory of a workflow run, or a
- * sub-directory of it.
- * 
- * @author Donal Fellows
- * @see File
- */
-public interface Directory extends DirectoryEntry {
-	/**
-	 * @return A list of the contents of the directory.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	Collection<DirectoryEntry> getContents() throws FilesystemAccessException;
-
-	/**
-	 * @return A list of the contents of the directory, in guaranteed date
-	 *         order.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	Collection<DirectoryEntry> getContentsByDate()
-			throws FilesystemAccessException;
-
-	/**
-	 * @return The contents of the directory (and its sub-directories) as a zip.
-	 * @throws FilesystemAccessException
-	 *             If things go wrong.
-	 */
-	ZipStream getContentsAsZip() throws FilesystemAccessException;
-
-	/**
-	 * Creates a sub-directory of this directory.
-	 * 
-	 * @param actor
-	 *            Who this is being created by.
-	 * @param name
-	 *            The name of the sub-directory.
-	 * @return A handle to the newly-created directory.
-	 * @throws FilesystemAccessException
-	 *             If the name is the same as some existing entry in the
-	 *             directory, or if something else goes wrong during creation.
-	 */
-	Directory makeSubdirectory(Principal actor, String name)
-			throws FilesystemAccessException;
-
-	/**
-	 * Creates an empty file in this directory.
-	 * 
-	 * @param actor
-	 *            Who this is being created by.
-	 * @param name
-	 *            The name of the file to create.
-	 * @return A handle to the newly-created file.
-	 * @throws FilesystemAccessException
-	 *             If the name is the same as some existing entry in the
-	 *             directory, or if something else goes wrong during creation.
-	 */
-	File makeEmptyFile(Principal actor, String name)
-			throws FilesystemAccessException;
-
-	/**
-	 * A simple pipe that produces the zipped contents of a directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class ZipStream extends PipedInputStream {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
deleted file mode 100644
index b098152..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.util.Date;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * An entry in a {@link Directory} representing a file or sub-directory.
- * 
- * @author Donal Fellows
- * @see Directory
- * @see File
- */
-public interface DirectoryEntry extends Comparable<DirectoryEntry> {
-	/**
-	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
-	 *         or contain the character "<tt>/</tt>".
-	 */
-	public String getName();
-
-	/**
-	 * @return The "full" name of the entry. This is computed relative to the
-	 *         workflow run's working directory. It may contain the "<tt>/</tt>"
-	 *         character.
-	 */
-	public String getFullName();
-
-	/**
-	 * @return The time that the entry was last modified.
-	 */
-	public Date getModificationDate();
-
-	/**
-	 * Destroy this directory entry, deleting the file or sub-directory. The
-	 * workflow run's working directory can never be manually destroyed.
-	 * 
-	 * @throws FilesystemAccessException
-	 *             If the destroy fails for some reason.
-	 */
-	public void destroy() throws FilesystemAccessException;
-	// TODO: Permissions (or decide not to do anything about them)
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
deleted file mode 100644
index e4e6590..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * Represents a file in the working directory of a workflow instance run, or in
- * some sub-directory of it.
- * 
- * @author Donal Fellows
- * @see Directory
- */
-public interface File extends DirectoryEntry {
-	/**
-	 * @param offset
-	 *            Where in the file to start reading.
-	 * @param length
-	 *            The length of file to read, or -1 to read to the end of the
-	 *            file.
-	 * @return The literal byte contents of the section of the file, or null if
-	 *         the section doesn't exist.
-	 * @throws FilesystemAccessException
-	 *             If the read of the file goes wrong.
-	 */
-	public byte[] getContents(int offset, int length)
-			throws FilesystemAccessException;
-
-	/**
-	 * Write the data to the file, totally replacing what was there before.
-	 * 
-	 * @param data
-	 *            The literal bytes that will form the new contents of the file.
-	 * @throws FilesystemAccessException
-	 *             If the write to the file goes wrong.
-	 */
-	public void setContents(byte[] data) throws FilesystemAccessException;
-
-	/**
-	 * Append the data to the file.
-	 * 
-	 * @param data
-	 *            The literal bytes that will be added on to the end of the
-	 *            file.
-	 * @throws FilesystemAccessException
-	 *             If the write to the file goes wrong.
-	 */
-	public void appendContents(byte[] data) throws FilesystemAccessException;
-
-	/**
-	 * @return The length of the file, in bytes.
-	 * @throws FilesystemAccessException
-	 *             If the read of the file size goes wrong.
-	 */
-	public long getSize() throws FilesystemAccessException;
-
-	/**
-	 * Asks for the argument file to be copied to this one.
-	 * 
-	 * @param from
-	 *            The source file.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	public void copy(File from) throws FilesystemAccessException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
deleted file mode 100644
index 31cb7cb..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-/**
- * This represents the assignment of inputs to input ports of the workflow. Note
- * that the <tt>file</tt> and <tt>value</tt> properties are never set at the
- * same time.
- * 
- * @author Donal Fellows
- */
-public interface Input {
-	/**
-	 * @return The file currently assigned to this input port, or <tt>null</tt>
-	 *         if no file is assigned.
-	 */
-	@Nullable
-	public String getFile();
-
-	/**
-	 * @return The name of this input port. This may not be changed.
-	 */
-	@Nonnull
-	public String getName();
-
-	/**
-	 * @return The value currently assigned to this input port, or <tt>null</tt>
-	 *         if no value is assigned.
-	 */
-	@Nullable
-	public String getValue();
-
-	/**
-	 * @return The delimiter for the input port, or <tt>null</tt> if the value
-	 *         is not to be split.
-	 */
-	@Nullable
-	public String getDelimiter();
-
-	/**
-	 * Sets the file to use for this input. This overrides the use of the
-	 * previous file and any set value.
-	 * 
-	 * @param file
-	 *            The filename to use. Must not start with a <tt>/</tt> or
-	 *            contain any <tt>..</tt> segments. Will be interpreted relative
-	 *            to the run's working directory.
-	 * @throws FilesystemAccessException
-	 *             If the filename is invalid.
-	 * @throws BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	public void setFile(String file) throws FilesystemAccessException,
-			BadStateChangeException;
-
-	/**
-	 * Sets the value to use for this input. This overrides the use of the
-	 * previous value and any set file.
-	 * 
-	 * @param value
-	 *            The value to use.
-	 * @throws BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	public void setValue(String value) throws BadStateChangeException;
-
-	/**
-	 * Sets (or clears) the delimiter for the input port.
-	 * 
-	 * @param delimiter
-	 *            The delimiter character, or <tt>null</tt> if the value is not
-	 *            to be split.
-	 * @throws BadStateChangeException
-	 *             If the run isn't in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	@Nullable
-	public void setDelimiter(String delimiter) throws BadStateChangeException;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
deleted file mode 100644
index d7998bc..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-import org.taverna.server.master.exceptions.NoListenerException;
-
-/**
- * An event listener that can be attached to a {@link TavernaRun}.
- * 
- * @author Donal Fellows
- */
-public interface Listener {
-	/**
-	 * @return The name of the listener.
-	 */
-	public String getName();
-
-	/**
-	 * @return The type of the listener.
-	 */
-	public String getType();
-
-	/**
-	 * @return The configuration document for the listener.
-	 */
-	public String getConfiguration();
-
-	/**
-	 * @return The supported properties of the listener.
-	 */
-	public String[] listProperties();
-
-	/**
-	 * Get the value of a particular property, which should be listed in the
-	 * {@link #listProperties()} method.
-	 * 
-	 * @param propName
-	 *            The name of the property to read.
-	 * @return The value of the property.
-	 * @throws NoListenerException
-	 *             If no property with that name exists.
-	 */
-	public String getProperty(String propName) throws NoListenerException;
-
-	/**
-	 * Set the value of a particular property, which should be listed in the
-	 * {@link #listProperties()} method.
-	 * 
-	 * @param propName
-	 *            The name of the property to write.
-	 * @param value
-	 *            The value to set the property to.
-	 * @throws NoListenerException
-	 *             If no property with that name exists.
-	 * @throws BadPropertyValueException
-	 *             If the value of the property is bad (e.g., wrong syntax).
-	 */
-	public void setProperty(String propName, String value)
-			throws NoListenerException, BadPropertyValueException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
deleted file mode 100644
index 37b104e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * This interface describes how to map from the identity understood by the
- * webapp to the identity understood by the local execution system.
- * 
- * @author Donal Fellows
- */
-public interface LocalIdentityMapper {
-	/**
-	 * Given a user's identity, get the local identity to use for executing
-	 * their workflows. Note that it is assumed that there will never be a
-	 * failure from this interface; it is <i>not</i> a security policy
-	 * decision or enforcement point.
-	 * 
-	 * @param user
-	 *            An identity token.
-	 * @return A user name, which must be defined in the context that workflows
-	 *         will be running in.
-	 */
-	public String getUsernameForPrincipal(UsernamePrincipal user);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
deleted file mode 100644
index 37dbf2c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import javax.annotation.Nonnull;
-
-/**
- * The interface supported by all notification message dispatchers.
- * @author Donal Fellows
- */
-public interface MessageDispatcher {
-	/**
-	 * @return Whether this message dispatcher is actually available (fully
-	 *         configured, etc.)
-	 */
-	boolean isAvailable();
-
-	/**
-	 * @return The name of this dispatcher, which must match the protocol
-	 *         supported by it (for a non-universal dispatcher) and the name of
-	 *         the message generator used to produce the message.
-	 */
-	String getName();
-
-	/**
-	 * Dispatch a message to a recipient.
-	 * 
-	 * @param originator
-	 *            The workflow run that produced the message.
-	 * @param messageSubject
-	 *            The subject of the message to send.
-	 * @param messageContent
-	 *            The plain-text content of the message to send.
-	 * @param targetParameter
-	 *            A description of where it is to go.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	void dispatch(@Nonnull TavernaRun originator,
-			@Nonnull String messageSubject, @Nonnull String messageContent,
-			@Nonnull String targetParameter) throws Exception;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
deleted file mode 100644
index f57fe71..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Simple policy interface.
- * 
- * @author Donal Fellows
- */
-public interface Policy {
-	/**
-	 * @return The maximum number of runs that the system can support.
-	 */
-	int getMaxRuns();
-
-	/**
-	 * Get the limit on the number of runs for this user.
-	 * 
-	 * @param user
-	 *            Who to get the limit for
-	 * @return The maximum number of runs for this user, or <tt>null</tt> if no
-	 *         per-user limit is imposed and only system-wide limits are to be
-	 *         enforced.
-	 */
-	Integer getMaxRuns(UsernamePrincipal user);
-
-	/**
-	 * Test whether the user can create an instance of the given workflow.
-	 * 
-	 * @param user
-	 *            Who wants to do the creation.
-	 * @param workflow
-	 *            The workflow they wish to instantiate.
-	 * @throws NoCreateException
-	 *             If they may not instantiate it.
-	 */
-	void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException;
-
-	/**
-	 * Test whether the user can destroy a workflow instance run or manipulate
-	 * its expiry date.
-	 * 
-	 * @param user
-	 *            Who wants to do the deletion.
-	 * @param run
-	 *            What they want to delete.
-	 * @throws NoDestroyException
-	 *             If they may not destroy it.
-	 */
-	void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException;
-
-	/**
-	 * Return whether the user has access to a particular workflow run.
-	 * <b>Note</b> that this does not throw any exceptions!
-	 * 
-	 * @param user
-	 *            Who wants to read the workflow's state.
-	 * @param run
-	 *            What do they want to read from.
-	 * @return Whether they can read it. Note that this check is always applied
-	 *         before testing whether the workflow can be updated or deleted by
-	 *         the user.
-	 */
-	boolean permitAccess(UsernamePrincipal user, TavernaRun run);
-
-	/**
-	 * Test whether the user can modify a workflow run (other than for its
-	 * expiry date).
-	 * 
-	 * @param user
-	 *            Who wants to do the modification.
-	 * @param run
-	 *            What they want to modify.
-	 * @throws NoUpdateException
-	 *             If they may not modify it.
-	 */
-	void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException;
-
-	/**
-	 * Get the URIs of the workflows that the given user may execute.
-	 * 
-	 * @param user
-	 *            Who are we finding out on behalf of.
-	 * @return A list of workflow URIs that they may instantiate, or
-	 *         <tt>null</tt> if any workflow may be submitted.
-	 */
-	List<URI> listPermittedWorkflowURIs(UsernamePrincipal user);
-
-	/**
-	 * @return The maximum number of {@linkplain Status#Operating operating}
-	 *         runs that the system can support.
-	 */
-	int getOperatingLimit();
-
-	/**
-	 * Set the URIs of the workflows that the given user may execute.
-	 * 
-	 * @param user
-	 *            Who are we finding out on behalf of.
-	 * @param permitted
-	 *            A list of workflow URIs that they may instantiate.
-	 */
-	void setPermittedWorkflowURIs(UsernamePrincipal user, List<URI> permitted);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
deleted file mode 100644
index b5e84c5..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.util.Map;
-
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Interface to the mechanism that looks after the mapping of names to runs.
- * Instances of this class may also be responsible for enforcing timely cleanup
- * of expired workflows.
- * 
- * @author Donal Fellows.
- */
-public interface RunStore {
-	/**
-	 * Obtain the workflow run for a given user and name.
-	 * 
-	 * @param user
-	 *            Who wants to do the lookup.
-	 * @param p
-	 *            The general policy system context.
-	 * @param uuid
-	 *            The handle for the run.
-	 * @return The workflow instance run.
-	 * @throws UnknownRunException
-	 *             If the lookup fails (either because it does not exist or
-	 *             because it is not permitted for the user by the policy).
-	 */
-	TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException;
-
-	/**
-	 * Obtain the named workflow run.
-	 * 
-	 * @param uuid
-	 *            The handle for the run.
-	 * @return The workflow instance run.
-	 * @throws UnknownRunException
-	 *             If the lookup fails (either because it does not exist or
-	 *             because it is not permitted for the user by the policy).
-	 */
-	public TavernaRun getRun(String uuid) throws UnknownRunException;
-
-	/**
-	 * List the runs that a particular user may access.
-	 * 
-	 * @param user
-	 *            Who wants to do the lookup, or <code>null</code> if it is
-	 *            being done "by the system" when the full mapping should be
-	 *            returned.
-	 * @param p
-	 *            The general policy system context.
-	 * @return A mapping from run names to run instances.
-	 */
-	Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p);
-
-	/**
-	 * Adds a workflow instance run to the store. Note that this operation is
-	 * <i>not</i> expected to be security-checked; that is the callers'
-	 * responsibility.
-	 * 
-	 * @param run
-	 *            The run itself.
-	 * @return The name of the run.
-	 */
-	String registerRun(TavernaRun run);
-
-	/**
-	 * Removes a run from the store. Note that this operation is <i>not</i>
-	 * expected to be security-checked; that is the callers' responsibility.
-	 * 
-	 * @param uuid
-	 *            The name of the run.
-	 */
-	void unregisterRun(String uuid);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
deleted file mode 100644
index 902c4d0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.io.Serializable;
-
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * How to create instances of a security context.
- * 
- * @author Donal Fellows
- */
-public interface SecurityContextFactory extends Serializable {
-	/**
-	 * Creates a security context.
-	 * 
-	 * @param run
-	 *            Handle to remote run. Allows the security context to know how
-	 *            to apply itself to the workflow run.
-	 * @param owner
-	 *            The identity of the owner of the workflow run.
-	 * @return The security context.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	TavernaSecurityContext create(TavernaRun run, UsernamePrincipal owner)
-			throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
deleted file mode 100644
index 399164d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-
-/**
- * The interface to a taverna workflow run, or "run" for short.
- * 
- * @author Donal Fellows
- */
-public interface TavernaRun extends Serializable {
-	/**
-	 * @return The identifier of the run.
-	 */
-	String getId();
-
-	/**
-	 * @return What was this run was create to execute.
-	 */
-	Workflow getWorkflow();
-
-	/**
-	 * @return The name of the run.
-	 */
-	String getName();
-
-	/**
-	 * @param name
-	 *            The new name of the run. May be truncated.
-	 */
-	void setName(String name);
-
-	/**
-	 * @return The name of the Baclava file to use for all inputs, or
-	 *         <tt>null</tt> if no Baclava file is set.
-	 */
-	String getInputBaclavaFile();
-
-	/**
-	 * Sets the Baclava file to use for all inputs. This overrides the use of
-	 * individual inputs.
-	 * 
-	 * @param filename
-	 *            The filename to use. Must not start with a <tt>/</tt> or
-	 *            contain any <tt>..</tt> segments. Will be interpreted relative
-	 *            to the run's working directory.
-	 * @throws FilesystemAccessException
-	 *             If the filename is invalid.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	void setInputBaclavaFile(String filename) throws FilesystemAccessException,
-			BadStateChangeException;
-
-	/**
-	 * @return The list of input assignments.
-	 */
-	List<Input> getInputs();
-
-	/**
-	 * Create an input assignment.
-	 * 
-	 * @param name
-	 *            The name of the port that this will be an input for.
-	 * @return The assignment reference.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	Input makeInput(String name) throws BadStateChangeException;
-
-	/**
-	 * @return The file (relative to the working directory) to write the outputs
-	 *         of the run to as a Baclava document, or <tt>null</tt> if they are
-	 *         to be written to non-Baclava files in a directory called
-	 *         <tt>out</tt>.
-	 */
-	String getOutputBaclavaFile();
-
-	/**
-	 * Sets where the output of the run is to be written to. This will cause the
-	 * output to be generated as a Baclava document, rather than a collection of
-	 * individual non-Baclava files in the subdirectory of the working directory
-	 * called <tt>out</tt>.
-	 * 
-	 * @param filename
-	 *            Where to write the Baclava file (or <tt>null</tt> to cause the
-	 *            output to be written to individual files); overwrites any
-	 *            previous setting of this value.
-	 * @throws FilesystemAccessException
-	 *             If the filename starts with a <tt>/</tt> or contains a
-	 *             <tt>..</tt> segment.
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 */
-	void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * @return When this run will expire, becoming eligible for automated
-	 *         deletion.
-	 */
-	Date getExpiry();
-
-	/**
-	 * Set when this run will expire.
-	 * 
-	 * @param d
-	 *            Expiry time. Deletion will happen some time after that.
-	 */
-	void setExpiry(Date d);
-
-	/**
-	 * @return The current status of the run.
-	 */
-	Status getStatus();
-
-	/**
-	 * Set the status of the run, which should cause it to move into the given
-	 * state. This may cause some significant changes.
-	 * 
-	 * @param s
-	 *            The state to try to change to.
-	 * @return <tt>null</tt>, or a string describing the incomplete state change
-	 *         if the operation has internally timed out.
-	 * @throws BadStateChangeException
-	 *             If the change to the given state is impossible.
-	 */
-	String setStatus(Status s) throws BadStateChangeException;
-
-	/**
-	 * @return Handle to the main working directory of the run.
-	 * @throws FilesystemAccessException
-	 */
-	Directory getWorkingDirectory() throws FilesystemAccessException;
-
-	/**
-	 * @return The list of listener instances attached to the run.
-	 */
-	List<Listener> getListeners();
-
-	/**
-	 * Add a listener to the run.
-	 * 
-	 * @param listener
-	 *            The listener to add.
-	 */
-	void addListener(Listener listener);
-
-	/**
-	 * @return The security context structure for this run.
-	 */
-	TavernaSecurityContext getSecurityContext();
-
-	/**
-	 * Kill off this run, removing all resources which it consumes.
-	 * 
-	 * @throws NoDestroyException
-	 *             If the destruction failed.
-	 */
-	void destroy() throws NoDestroyException;
-
-	/**
-	 * @return When this workflow run was created.
-	 */
-	Date getCreationTimestamp();
-
-	/**
-	 * @return When this workflow run was started, or <tt>null</tt> if it has
-	 *         never been started.
-	 */
-	Date getStartTimestamp();
-
-	/**
-	 * @return When this workflow run was found to have finished, or
-	 *         <tt>null</tt> if it has never finished (either still running or
-	 *         never started).
-	 */
-	Date getFinishTimestamp();
-
-	/**
-	 * Test if this run is really there.
-	 * 
-	 * <p>
-	 * <i>Implementation note:</i> Used to test communication fabrics, etc. so
-	 * implementations of this interface that do not delegate to another object
-	 * should do nothing.
-	 * 
-	 * @throws UnknownRunException
-	 *             If things fail.
-	 */
-	void ping() throws UnknownRunException;
-
-	/**
-	 * @return whether the run generates provenance data
-	 */
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param generateProvenance
-	 *            whether the run generates provenance data
-	 */
-	void setGenerateProvenance(boolean generateProvenance);
-}


[16/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
new file mode 100644
index 0000000..06202dc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/StrippedDownAuthProvider.java
@@ -0,0 +1,278 @@
+package org.taverna.server.master.identity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.CredentialsExpiredException;
+import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.LockedException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+
+/**
+ * A stripped down version of a
+ * {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider
+ * DaoAuthenticationProvider}/
+ * {@link org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider
+ * AbstractUserDetailsAuthenticationProvider} that avoids much of the overhead
+ * associated with that class.
+ */
+public class StrippedDownAuthProvider implements AuthenticationProvider {
+	/**
+	 * The plaintext password used to perform
+	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
+	 * the user is not found to avoid SEC-2056.
+	 */
+	private static final String USER_NOT_FOUND_PASSWORD = "userNotFoundPassword";
+
+	/**
+	 * The password used to perform
+	 * {@link PasswordEncoder#isPasswordValid(String, String, Object)} on when
+	 * the user is not found to avoid SEC-2056. This is necessary, because some
+	 * {@link PasswordEncoder} implementations will short circuit if the
+	 * password is not in a valid format.
+	 */
+	private String userNotFoundEncodedPassword;
+	private UserDetailsService userDetailsService;
+	private PasswordEncoder passwordEncoder;
+	private Map<String, AuthCacheEntry> authCache = new HashMap<>();
+	protected final Log logger = LogFactory.getLog(getClass());
+
+	private static class AuthCacheEntry {
+		private String creds;
+		private long timestamp;
+		private static final long VALIDITY = 1000 * 60 * 20;
+		AuthCacheEntry(String credentials) {
+			creds = credentials;
+			timestamp = System.currentTimeMillis();
+		}
+		boolean valid(String password) {
+			return creds.equals(password) && timestamp+VALIDITY > System.currentTimeMillis();
+		}
+	}
+
+	@PerfLogged
+	@Override
+	public Authentication authenticate(Authentication authentication)
+			throws AuthenticationException {
+
+		if (!(authentication instanceof UsernamePasswordAuthenticationToken))
+			throw new IllegalArgumentException(
+					"can only authenticate against username+password");
+		UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
+
+		// Determine username
+		String username = (auth.getPrincipal() == null) ? "NONE_PROVIDED"
+				: auth.getName();
+
+		UserDetails user;
+
+		try {
+			user = retrieveUser(username, auth);
+			if (user == null)
+				throw new IllegalStateException(
+						"retrieveUser returned null - a violation of the interface contract");
+		} catch (UsernameNotFoundException notFound) {
+			if (logger.isDebugEnabled())
+				logger.debug("User '" + username + "' not found", notFound);
+			throw new BadCredentialsException("Bad credentials");
+		}
+
+		// Pre-auth
+		if (!user.isAccountNonLocked())
+			throw new LockedException("User account is locked");
+		if (!user.isEnabled())
+			throw new DisabledException("User account is disabled");
+		if (!user.isAccountNonExpired())
+			throw new AccountExpiredException("User account has expired");
+		Object credentials = auth.getCredentials();
+		if (credentials == null) {
+			logger.debug("Authentication failed: no credentials provided");
+
+			throw new BadCredentialsException("Bad credentials");
+		}
+
+		String providedPassword = credentials.toString();
+		boolean matched = false;
+		synchronized (authCache) {
+			AuthCacheEntry pw = authCache.get(username);
+			if (pw != null && providedPassword != null) {
+				if (pw.valid(providedPassword))
+					matched = true;
+				else
+					authCache.remove(username);
+			}
+		}
+		// Auth
+		if (!matched) {
+			if (!passwordEncoder.matches(providedPassword, user.getPassword())) {
+				logger.debug("Authentication failed: password does not match stored value");
+
+				throw new BadCredentialsException("Bad credentials");
+			}
+			if (providedPassword != null)
+				synchronized (authCache) {
+					authCache.put(username, new AuthCacheEntry(providedPassword));
+				}
+		}
+
+		// Post-auth
+		if (!user.isCredentialsNonExpired())
+			throw new CredentialsExpiredException(
+					"User credentials have expired");
+
+		return createSuccessAuthentication(user, auth, user);
+	}
+
+	@PreDestroy
+	void clearCache() {
+		authCache.clear();
+	}
+
+	/**
+	 * Creates a successful {@link Authentication} object.
+	 * <p>
+	 * Protected so subclasses can override.
+	 * </p>
+	 * <p>
+	 * Subclasses will usually store the original credentials the user supplied
+	 * (not salted or encoded passwords) in the returned
+	 * <code>Authentication</code> object.
+	 * </p>
+	 * 
+	 * @param principal
+	 *            that should be the principal in the returned object (defined
+	 *            by the {@link #isForcePrincipalAsString()} method)
+	 * @param authentication
+	 *            that was presented to the provider for validation
+	 * @param user
+	 *            that was loaded by the implementation
+	 * 
+	 * @return the successful authentication token
+	 */
+	private Authentication createSuccessAuthentication(Object principal,
+			Authentication authentication, UserDetails user) {
+		/*
+		 * Ensure we return the original credentials the user supplied, so
+		 * subsequent attempts are successful even with encoded passwords. Also
+		 * ensure we return the original getDetails(), so that future
+		 * authentication events after cache expiry contain the details
+		 */
+		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
+				principal, authentication.getCredentials(),
+				user.getAuthorities());
+		result.setDetails(authentication.getDetails());
+
+		return result;
+	}
+
+	@Override
+	public boolean supports(Class<?> authentication) {
+		return UsernamePasswordAuthenticationToken.class
+				.isAssignableFrom(authentication);
+	}
+
+	/**
+	 * Allows subclasses to actually retrieve the <code>UserDetails</code> from
+	 * an implementation-specific location, with the option of throwing an
+	 * <code>AuthenticationException</code> immediately if the presented
+	 * credentials are incorrect (this is especially useful if it is necessary
+	 * to bind to a resource as the user in order to obtain or generate a
+	 * <code>UserDetails</code>).
+	 * <p>
+	 * Subclasses are not required to perform any caching, as the
+	 * <code>AbstractUserDetailsAuthenticationProvider</code> will by default
+	 * cache the <code>UserDetails</code>. The caching of
+	 * <code>UserDetails</code> does present additional complexity as this means
+	 * subsequent requests that rely on the cache will need to still have their
+	 * credentials validated, even if the correctness of credentials was assured
+	 * by subclasses adopting a binding-based strategy in this method.
+	 * Accordingly it is important that subclasses either disable caching (if
+	 * they want to ensure that this method is the only method that is capable
+	 * of authenticating a request, as no <code>UserDetails</code> will ever be
+	 * cached) or ensure subclasses implement
+	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
+	 * to compare the credentials of a cached <code>UserDetails</code> with
+	 * subsequent authentication requests.
+	 * </p>
+	 * <p>
+	 * Most of the time subclasses will not perform credentials inspection in
+	 * this method, instead performing it in
+	 * {@link #additionalAuthenticationChecks(UserDetails, UsernamePasswordAuthenticationToken)}
+	 * so that code related to credentials validation need not be duplicated
+	 * across two methods.
+	 * </p>
+	 * 
+	 * @param username
+	 *            The username to retrieve
+	 * @param authentication
+	 *            The authentication request, which subclasses <em>may</em> need
+	 *            to perform a binding-based retrieval of the
+	 *            <code>UserDetails</code>
+	 * 
+	 * @return the user information (never <code>null</code> - instead an
+	 *         exception should the thrown)
+	 * 
+	 * @throws AuthenticationException
+	 *             if the credentials could not be validated (generally a
+	 *             <code>BadCredentialsException</code>, an
+	 *             <code>AuthenticationServiceException</code> or
+	 *             <code>UsernameNotFoundException</code>)
+	 */
+	private UserDetails retrieveUser(String username,
+			UsernamePasswordAuthenticationToken authentication)
+			throws AuthenticationException {
+		try {
+			return userDetailsService.loadUserByUsername(username);
+		} catch (UsernameNotFoundException notFound) {
+			if (authentication.getCredentials() != null) {
+				String presentedPassword = authentication.getCredentials()
+						.toString();
+				passwordEncoder.matches(presentedPassword,
+						userNotFoundEncodedPassword);
+			}
+			throw notFound;
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception repositoryProblem) {
+			throw new AuthenticationServiceException(
+					repositoryProblem.getMessage(), repositoryProblem);
+		}
+	}
+
+	/**
+	 * Sets the PasswordEncoder instance to be used to encode and validate
+	 * passwords.
+	 */
+	@Required
+	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+		if (passwordEncoder == null)
+			throw new IllegalArgumentException("passwordEncoder cannot be null");
+
+		this.passwordEncoder = passwordEncoder;
+		this.userNotFoundEncodedPassword = passwordEncoder
+				.encode(USER_NOT_FOUND_PASSWORD);
+	}
+
+	@Required
+	public void setUserDetailsService(UserDetailsService userDetailsService) {
+		if (userDetailsService == null)
+			throw new IllegalStateException("A UserDetailsService must be set");
+		this.userDetailsService = userDetailsService;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
new file mode 100644
index 0000000..bdb6e40
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/User.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.Query;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * The representation of a user in the database.
+ * <p>
+ * A user consists logically of a (non-ordered) tuple of items:
+ * <ul>
+ * <li>The {@linkplain #getUsername() user name},
+ * <li>The {@linkplain #getPassword() user's password} (salted, encoded),
+ * <li>Whether the user is {@linkplain #isEnabled() enabled} (i.e., able to log
+ * in),
+ * <li>Whether the user has {@linkplain #isAdmin() administrative privileges}, and
+ * <li>What {@linkplain #getLocalUsername() system (Unix) account} the user's
+ * workflows will run as; separation between different users that are mapped to
+ * the same system account is nothing like as strongly enforced.
+ * </ul>
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(schema = "USERS", table = "LIST")
+@Query(name = "users", language = "SQL", value = "SELECT id FROM USERS.LIST ORDER BY id", resultClass = String.class)
+@XmlRootElement
+@XmlType(name = "User", propOrder = {})
+@SuppressWarnings("serial")
+public class User implements UserDetails {
+	@XmlElement
+	@Persistent
+	private boolean disabled;
+	@XmlElement(name = "username", required = true)
+	@Persistent(primaryKey = "true")
+	private String id;
+	@XmlElement(name = "password", required = true)
+	@Persistent(column = "password")
+	private String encodedPassword;
+	@XmlElement
+	@Persistent
+	private boolean admin;
+	@XmlElement
+	@Persistent
+	private String localUsername;
+
+	@Override
+	public Collection<GrantedAuthority> getAuthorities() {
+		List<GrantedAuthority> auths = new ArrayList<>();
+		auths.add(new LiteralGrantedAuthority(USER));
+		if (admin)
+			auths.add(new LiteralGrantedAuthority(ADMIN));
+		if (localUsername != null)
+			auths.add(new LiteralGrantedAuthority(AUTHORITY_PREFIX
+					+ localUsername));
+		return auths;
+	}
+
+	@Override
+	public String getPassword() {
+		return encodedPassword;
+	}
+
+	@Override
+	public String getUsername() {
+		return id;
+	}
+
+	@Override
+	public boolean isAccountNonExpired() {
+		return true;
+	}
+
+	@Override
+	public boolean isAccountNonLocked() {
+		return true;
+	}
+
+	@Override
+	public boolean isCredentialsNonExpired() {
+		return true;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return !disabled;
+	}
+
+	void setDisabled(boolean disabled) {
+		this.disabled = disabled;
+	}
+
+	void setUsername(String username) {
+		this.id = username;
+	}
+
+	void setEncodedPassword(String password) {
+		this.encodedPassword = password;
+	}
+
+	void setAdmin(boolean admin) {
+		this.admin = admin;
+	}
+
+	public boolean isAdmin() {
+		return admin;
+	}
+
+	void setLocalUsername(String localUsername) {
+		this.localUsername = localUsername;
+	}
+
+	public String getLocalUsername() {
+		return localUsername;
+	}
+}
+
+@SuppressWarnings("serial")
+class LiteralGrantedAuthority implements GrantedAuthority {
+	private String auth;
+
+	LiteralGrantedAuthority(String auth) {
+		this.auth = auth;
+	}
+
+	@Override
+	public String getAuthority() {
+		return auth;
+	}
+
+	@Override
+	public String toString() {
+		return "AUTHORITY(" + auth + ")";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
new file mode 100644
index 0000000..054d932
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStore.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedOperationParameter;
+import org.springframework.jmx.export.annotation.ManagedOperationParameters;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.core.userdetails.memory.UserAttribute;
+import org.springframework.security.core.userdetails.memory.UserAttributeEditor;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.JDOSupport;
+
+/**
+ * The bean class that is responsible for managing the users in the database.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+@ManagedResource(objectName = JMX_ROOT + "Users", description = "The user database.")
+public class UserStore extends JDOSupport<User> implements UserDetailsService,
+		UserStoreAPI {
+	/** The logger for the user store. */
+	private transient Log log = getLog("Taverna.Server.UserDB");
+
+	public UserStore() {
+		super(User.class);
+	}
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private Map<String, BootstrapUserInfo> base = new HashMap<>();
+	private String defLocalUser;
+	private PasswordEncoder encoder;
+	private volatile int epoch;
+
+	/**
+	 * Install the encoder that will be used to turn a plaintext password into
+	 * something that it is safe to store in the database.
+	 * 
+	 * @param encoder
+	 *            The password encoder bean to install.
+	 */
+	public void setEncoder(PasswordEncoder encoder) {
+		this.encoder = encoder;
+	}
+
+	public void setBaselineUserProperties(Properties props) {
+		UserAttributeEditor parser = new UserAttributeEditor();
+
+		for (Object name : props.keySet()) {
+			String username = (String) name;
+			String value = props.getProperty(username);
+
+			// Convert value to a password, enabled setting, and list of granted
+			// authorities
+			parser.setAsText(value);
+
+			UserAttribute attr = (UserAttribute) parser.getValue();
+			if (attr != null && attr.isEnabled())
+				base.put(username, new BootstrapUserInfo(username, attr));
+		}
+	}
+
+	private void installPassword(User u, String password) {
+		u.setEncodedPassword(encoder.encode(password));
+	}
+
+	public void setDefaultLocalUser(String defLocalUser) {
+		this.defLocalUser = defLocalUser;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> getUsers() {
+		return (List<String>) namedQuery("users").execute();
+	}
+
+	@WithinSingleTransaction
+	@PostConstruct
+	void initDB() {
+		if (base == null || base.isEmpty())
+			log.warn("no baseline user collection");
+		else if (!getUsers().isEmpty())
+			log.info("using existing users from database");
+		else
+			for (String username : base.keySet()) {
+				BootstrapUserInfo ud = base.get(username);
+				if (ud == null)
+					continue;
+				User u = ud.get(encoder);
+				if (u == null)
+					continue;
+				log.info("bootstrapping user " + username + " in the database");
+				persist(u);
+			}
+		base = null;
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedAttribute(description = "The list of server accounts known about.", currencyTimeLimit = 30)
+	public List<String> getUserNames() {
+		return getUsers();
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	public User getUser(String userName) {
+		return detach(getById(userName));
+	}
+
+	/**
+	 * Get information about a server account.
+	 * 
+	 * @param userName
+	 *            The username to look up.
+	 * @return A description map intended for use by a server admin over JMX.
+	 */
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Get information about a server account.")
+	@ManagedOperationParameters(@ManagedOperationParameter(name = "userName", description = "The username to look up."))
+	public Map<String, String> getUserInfo(String userName) {
+		User u = getById(userName);
+		Map<String, String> info = new HashMap<>();
+		info.put("name", u.getUsername());
+		info.put("admin", u.isAdmin() ? "yes" : "no");
+		info.put("enabled", u.isEnabled() ? "yes" : "no");
+		info.put("localID", u.getLocalUsername());
+		return info;
+	}
+
+	/**
+	 * Get a list of all the users in the database.
+	 * 
+	 * @return A list of user details, <i>copied</i> out of the database.
+	 */
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<UserDetails> listUsers() {
+		ArrayList<UserDetails> result = new ArrayList<>();
+		for (String id : getUsers())
+			result.add(detach(getById(id)));
+		return result;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Create a new user account; the account will be disabled and "
+			+ "non-administrative by default. Does not create any underlying system account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to create."),
+			@ManagedOperationParameter(name = "password", description = "The password to use."),
+			@ManagedOperationParameter(name = "coupleLocalUsername", description = "Whether to set the local user name to the 'main' one.") })
+	public void addUser(String username, String password,
+			boolean coupleLocalUsername) {
+		if (username.matches(".*[^a-zA-Z0-9].*"))
+			throw new IllegalArgumentException(
+					"bad user name; must be pure alphanumeric");
+		if (getById(username) != null)
+			throw new IllegalArgumentException("user name already exists");
+		User u = new User();
+		u.setDisabled(true);
+		u.setAdmin(false);
+		u.setUsername(username);
+		installPassword(u, password);
+		if (coupleLocalUsername)
+			u.setLocalUsername(username);
+		else
+			u.setLocalUsername(defLocalUser);
+		log.info("creating user for " + username);
+		persist(u);
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Set or clear whether this account is enabled. "
+			+ "Disabled accounts cannot be used to log in.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "enabled", description = "Whether to enable the account.") })
+	public void setUserEnabled(String username, boolean enabled) {
+		User u = getById(username);
+		if (u != null) {
+			u.setDisabled(!enabled);
+			log.info((enabled ? "enabling" : "disabling") + " user " + username);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Set or clear the mark on an account that indicates "
+			+ "that it has administrative privileges.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "admin", description = "Whether the account has admin privileges.") })
+	public void setUserAdmin(String username, boolean admin) {
+		User u = getById(username);
+		if (u != null) {
+			u.setAdmin(admin);
+			log.info((admin ? "enabling" : "disabling") + " user " + username
+					+ " admin status");
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Change the password for an account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "password", description = "The new password to use.") })
+	public void setUserPassword(String username, String password) {
+		User u = getById(username);
+		if (u != null) {
+			installPassword(u, password);
+			log.info("changing password for user " + username);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Change what local system account to use for a server account.")
+	@ManagedOperationParameters({
+			@ManagedOperationParameter(name = "username", description = "The username to adjust."),
+			@ManagedOperationParameter(name = "password", description = "The new local user account use.") })
+	public void setUserLocalUser(String username, String localUsername) {
+		User u = getById(username);
+		if (u != null) {
+			u.setLocalUsername(localUsername);
+			log.info("mapping user " + username + " to local account "
+					+ localUsername);
+			epoch++;
+		}
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	@ManagedOperation(description = "Delete a server account. The underlying "
+			+ "system account is not modified.")
+	@ManagedOperationParameters(@ManagedOperationParameter(name = "username", description = "The username to delete."))
+	public void deleteUser(String username) {
+		delete(getById(username));
+		log.info("deleting user " + username);
+		epoch++;
+	}
+
+	@Override
+	@PerfLogged
+	@WithinSingleTransaction
+	public UserDetails loadUserByUsername(String username)
+			throws UsernameNotFoundException, DataAccessException {
+		User u;
+		if (base != null) {
+			log.warn("bootstrap user store still installed!");
+			BootstrapUserInfo ud = base.get(username);
+			if (ud != null) {
+				log.warn("retrieved production credentials for " + username
+						+ " from bootstrap store");
+				u = ud.get(encoder);
+				if (u != null)
+					return u;
+			}
+		}
+		try {
+			u = detach(getById(username));
+		} catch (NullPointerException npe) {
+			throw new UsernameNotFoundException("who are you?");
+		} catch (Exception ex) {
+			throw new UsernameNotFoundException("who are you?", ex);
+		}
+		if (u != null)
+			return u;
+		throw new UsernameNotFoundException("who are you?");
+	}
+
+	int getEpoch() {
+		return epoch;
+	}
+
+	public static class CachedUserStore implements UserDetailsService {
+		private int epoch;
+		private Map<String, UserDetails> cache = new HashMap<>();
+		private UserStore realStore;
+
+		@Required
+		public void setRealStore(UserStore store) {
+			this.realStore = store;
+		}
+
+		@Override
+		@PerfLogged
+		public UserDetails loadUserByUsername(String username) {
+			int epoch = realStore.getEpoch();
+			UserDetails details;
+			synchronized (cache) {
+				if (epoch != this.epoch) {
+					cache.clear();
+					this.epoch = epoch;
+					details = null;
+				} else
+					details = cache.get(username);
+			}
+			if (details == null) {
+				details = realStore.loadUserByUsername(username);
+				synchronized (cache) {
+					cache.put(username, details);
+				}
+			}
+			return details;
+		}
+	}
+
+	private static class BootstrapUserInfo {
+		private String user;
+		private String pass;
+		private Collection<GrantedAuthority> auth;
+
+		BootstrapUserInfo(String username, UserAttribute attr) {
+			user = username;
+			pass = attr.getPassword();
+			auth = attr.getAuthorities();
+		}
+
+		User get(PasswordEncoder encoder) {
+			User u = new User();
+			boolean realUser = false;
+			for (GrantedAuthority ga : auth) {
+				String a = ga.getAuthority();
+				if (a.startsWith(AUTHORITY_PREFIX))
+					u.setLocalUsername(a.substring(AUTHORITY_PREFIX.length()));
+				else if (a.equals(USER))
+					realUser = true;
+				else if (a.equals(ADMIN))
+					u.setAdmin(true);
+			}
+			if (!realUser)
+				return null;
+			u.setUsername(user);
+			u.setEncodedPassword(encoder.encode(pass));
+			u.setDisabled(false);
+			return u;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
new file mode 100644
index 0000000..a048da9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/UserStoreAPI.java
@@ -0,0 +1,91 @@
+package org.taverna.server.master.identity;
+
+import java.util.List;
+
+/**
+ * The API that is exposed by the DAO that exposes user management.
+ * 
+ * @author Donal Fellows
+ * @see User
+ */
+public interface UserStoreAPI {
+	/**
+	 * List the currently-known account names.
+	 * 
+	 * @return A list of users in the database. Note that this is a snapshot.
+	 */
+	List<String> getUserNames();
+
+	/**
+	 * Get a particular user's description.
+	 * 
+	 * @param userName
+	 *            The username to look up.
+	 * @return A <i>copy</i> of the user description.
+	 */
+	User getUser(String userName);
+
+	/**
+	 * Create a new user account; the account will be disabled and
+	 * non-administrative by default. Does not create any underlying system
+	 * account.
+	 * 
+	 * @param username
+	 *            The username to create.
+	 * @param password
+	 *            The password to use.
+	 * @param coupleLocalUsername
+	 *            Whether to set the local user name to the 'main' one.
+	 */
+	void addUser(String username, String password, boolean coupleLocalUsername);
+
+	/**
+	 * Set or clear whether this account is enabled. Disabled accounts cannot be
+	 * used to log in.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param enabled
+	 *            Whether to enable the account.
+	 */
+	void setUserEnabled(String username, boolean enabled);
+
+	/**
+	 * Set or clear the mark on an account that indicates that it has
+	 * administrative privileges.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param admin
+	 *            Whether the account has admin privileges.
+	 */
+	void setUserAdmin(String username, boolean admin);
+
+	/**
+	 * Change the password for an account.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param password
+	 *            The new password to use.
+	 */
+	void setUserPassword(String username, String password);
+
+	/**
+	 * Change what local system account to use for a server account.
+	 * 
+	 * @param username
+	 *            The username to adjust.
+	 * @param localUsername
+	 *            The new local user account use.
+	 */
+	void setUserLocalUser(String username, String localUsername);
+
+	/**
+	 * Delete a server account. The underlying system account is not modified.
+	 * 
+	 * @param username
+	 *            The username to delete.
+	 */
+	void deleteUser(String username);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
new file mode 100644
index 0000000..9219a60
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/WorkflowInternalAuthProvider.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE.txt" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static java.util.Collections.synchronizedMap;
+import static org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes;
+import static org.taverna.server.master.common.Roles.SELF;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.authentication.AuthenticationServiceException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.worker.RunDatabaseDAO;
+
+/**
+ * A special authentication provider that allows a workflow to authenticate to
+ * itself. This is used to allow the workflow to publish to its own interaction
+ * feed.
+ * 
+ * @author Donal Fellows
+ */
+public class WorkflowInternalAuthProvider extends
+		AbstractUserDetailsAuthenticationProvider {
+	private Log log = LogFactory.getLog("Taverna.Server.UserDB");
+	private static final boolean logDecisions = true;
+	public static final String PREFIX = "wfrun_";
+	private RunDatabaseDAO dao;
+	private Map<String, String> cache;
+
+	@Required
+	public void setDao(RunDatabaseDAO dao) {
+		this.dao = dao;
+	}
+
+	@Required
+	@SuppressWarnings("serial")
+	public void setCacheBound(final int bound) {
+		cache = synchronizedMap(new LinkedHashMap<String, String>() {
+			@Override
+			protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
+				return size() > bound;
+			}
+		});
+	}
+
+	public void setAuthorizedAddresses(String[] addresses) {
+		authorizedAddresses = new HashSet<>(localAddresses);
+		for (String s : addresses)
+			authorizedAddresses.add(s);
+	}
+
+	@PostConstruct
+	public void logConfig() {
+		log.info("authorized addresses for automatic access: "
+				+ authorizedAddresses);
+	}
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private final Set<String> localAddresses = new HashSet<>();
+	private Set<String> authorizedAddresses;
+	{
+		localAddresses.add("127.0.0.1"); // IPv4
+		localAddresses.add("::1"); // IPv6
+		try {
+			InetAddress addr = InetAddress.getLocalHost();
+			if (!addr.isLoopbackAddress())
+				localAddresses.add(addr.getHostAddress());
+		} catch (UnknownHostException e) {
+			// Ignore the exception
+		}
+		authorizedAddresses = new HashSet<>(localAddresses);
+	}
+
+	/**
+	 * Check that the authentication request is actually valid for the given
+	 * user record.
+	 * 
+	 * @param userRecord
+	 *            as retrieved from the
+	 *            {@link #retrieveUser(String, UsernamePasswordAuthenticationToken)}
+	 *            or <code>UserCache</code>
+	 * @param principal
+	 *            the principal that is trying to authenticate (and that we're
+	 *            trying to bind)
+	 * @param credentials
+	 *            the credentials (e.g., password) presented by the principal
+	 * 
+	 * @throws AuthenticationException
+	 *             AuthenticationException if the credentials could not be
+	 *             validated (generally a <code>BadCredentialsException</code>,
+	 *             an <code>AuthenticationServiceException</code>)
+	 * @throws Exception
+	 *             If something goes wrong. Will be logged and converted to a
+	 *             generic AuthenticationException.
+	 */
+	protected void additionalAuthenticationChecks(UserDetails userRecord,
+			@Nonnull Object principal, @Nonnull Object credentials)
+			throws Exception {
+		@Nonnull
+		HttpServletRequest req = ((ServletRequestAttributes) currentRequestAttributes())
+				.getRequest();
+
+		// Are we coming from a "local" address?
+		if (!req.getLocalAddr().equals(req.getRemoteAddr())
+				&& !authorizedAddresses.contains(req.getRemoteAddr())) {
+			if (logDecisions)
+				log.info("attempt to use workflow magic token from untrusted address:"
+						+ " token="
+						+ userRecord.getUsername()
+						+ ", address="
+						+ req.getRemoteAddr());
+			throw new BadCredentialsException("bad login token");
+		}
+
+		// Does the password match?
+		if (!credentials.equals(userRecord.getPassword())) {
+			if (logDecisions)
+				log.info("workflow magic token is untrusted due to password mismatch:"
+						+ " wanted="
+						+ userRecord.getPassword()
+						+ ", got="
+						+ credentials);
+			throw new BadCredentialsException("bad login token");
+		}
+
+		if (logDecisions)
+			log.info("granted role " + SELF + " to user "
+					+ userRecord.getUsername());
+	}
+
+	/**
+	 * Retrieve the <code>UserDetails</code> from the relevant store, with the
+	 * option of throwing an <code>AuthenticationException</code> immediately if
+	 * the presented credentials are incorrect (this is especially useful if it
+	 * is necessary to bind to a resource as the user in order to obtain or
+	 * generate a <code>UserDetails</code>).
+	 * 
+	 * @param username
+	 *            The username to retrieve
+	 * @param details
+	 *            The details from the authentication request.
+	 * @see #retrieveUser(String,UsernamePasswordAuthenticationToken)
+	 * @return the user information (never <code>null</code> - instead an
+	 *         exception should the thrown)
+	 * @throws AuthenticationException
+	 *             if the credentials could not be validated (generally a
+	 *             <code>BadCredentialsException</code>, an
+	 *             <code>AuthenticationServiceException</code> or
+	 *             <code>UsernameNotFoundException</code>)
+	 * @throws Exception
+	 *             If something goes wrong. It will be logged and converted into
+	 *             a general AuthenticationException.
+	 */
+	@Nonnull
+	protected UserDetails retrieveUser(String username, Object details)
+			throws Exception {
+		if (details == null || !(details instanceof WebAuthenticationDetails))
+			throw new UsernameNotFoundException("context unsupported");
+		if (!username.startsWith(PREFIX))
+			throw new UsernameNotFoundException(
+					"unsupported username for this provider");
+		if (logDecisions)
+			log.info("request for auth for user " + username);
+		String wfid = username.substring(PREFIX.length());
+		String securityToken;
+		try {
+			securityToken = cache.get(wfid);
+			if (securityToken == null) {
+				securityToken = dao.getSecurityToken(wfid);
+				if (securityToken == null)
+					throw new UsernameNotFoundException("no such user");
+				cache.put(wfid, securityToken);
+			}
+		} catch (NullPointerException npe) {
+			throw new UsernameNotFoundException("no such user");
+		}
+		return new User(username, securityToken, true, true, true, true,
+				Arrays.asList(new LiteralGrantedAuthority(SELF),
+						new WorkflowSelfAuthority(wfid)));
+	}
+
+	@Override
+	@PerfLogged
+	protected final void additionalAuthenticationChecks(UserDetails userRecord,
+			UsernamePasswordAuthenticationToken token) {
+		try {
+			additionalAuthenticationChecks(userRecord, token.getPrincipal(),
+					token.getCredentials());
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception e) {
+			log.warn("unexpected failure in authentication", e);
+			throw new AuthenticationServiceException(
+					"unexpected failure in authentication", e);
+		}
+	}
+
+	@Override
+	@Nonnull
+	@PerfLogged
+	protected final UserDetails retrieveUser(String username,
+			UsernamePasswordAuthenticationToken token) {
+		try {
+			return retrieveUser(username, token.getDetails());
+		} catch (AuthenticationException e) {
+			throw e;
+		} catch (Exception e) {
+			log.warn("unexpected failure in authentication", e);
+			throw new AuthenticationServiceException(
+					"unexpected failure in authentication", e);
+		}
+	}
+
+	@SuppressWarnings("serial")
+	public static class WorkflowSelfAuthority extends LiteralGrantedAuthority {
+		public WorkflowSelfAuthority(String wfid) {
+			super(wfid);
+		}
+
+		public String getWorkflowID() {
+			return getAuthority();
+		}
+
+		@Override
+		public String toString() {
+			return "WORKFLOW(" + getAuthority() + ")";
+		}
+	}
+
+	public static class WorkflowSelfIDMapper implements LocalIdentityMapper {
+		private Log log = LogFactory.getLog("Taverna.Server.UserDB");
+		private RunStore runStore;
+
+		@PreDestroy
+		void closeLog() {
+			log = null;
+		}
+
+		@Required
+		public void setRunStore(RunStore runStore) {
+			this.runStore = runStore;
+		}
+
+		private String getUsernameForSelfAccess(WorkflowSelfAuthority authority)
+				throws UnknownRunException {
+			return runStore.getRun(authority.getWorkflowID())
+					.getSecurityContext().getOwner().getName();
+		}
+
+		@Override
+		@PerfLogged
+		public String getUsernameForPrincipal(UsernamePrincipal user) {
+			Authentication auth = SecurityContextHolder.getContext()
+					.getAuthentication();
+			if (auth == null || !auth.isAuthenticated())
+				return null;
+			try {
+				for (GrantedAuthority authority : auth.getAuthorities())
+					if (authority instanceof WorkflowSelfAuthority)
+						return getUsernameForSelfAccess((WorkflowSelfAuthority) authority);
+			} catch (UnknownRunException e) {
+				log.warn("workflow run disappeared during computation of workflow map identity");
+			}
+			return null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
new file mode 100644
index 0000000..dd1500a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Implementations of beans that map global user identities to local
+ * usernames.
+ */
+package org.taverna.server.master.identity;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
new file mode 100644
index 0000000..99e1d99
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/InteractionFeedSupport.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interaction;
+
+import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
+import static java.util.Collections.reverse;
+import static javax.management.Query.attr;
+import static javax.management.Query.match;
+import static javax.management.Query.value;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.TavernaServerSupport;
+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.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Bean that supports interaction feeds. This glues together the Abdera
+ * serialization engine and the directory-based model used inside the server.
+ * 
+ * @author Donal Fellows
+ */
+public class InteractionFeedSupport {
+	/**
+	 * The name of the resource within the run resource that is the run's
+	 * interaction feed resource.
+	 */
+	public static final String FEED_URL_DIR = "interaction";
+	/**
+	 * The name of the directory below the run working directory that will
+	 * contain the entries of the interaction feed.
+	 */
+	public static final String FEED_DIR = "feed";
+	/**
+	 * Should the contents of the entry be stripped when describing the overall
+	 * feed? This makes sense if (and only if) large entries are being pushed
+	 * through the feed.
+	 */
+	private static final boolean STRIP_CONTENTS = false;
+	/** Maximum size of an entry before truncation. */
+	private static final long MAX_ENTRY_SIZE = 50 * 1024;
+	/** Extension for entry files. */
+	private static final String EXT = ".atom";
+
+	private TavernaServerSupport support;
+	private FilenameUtils utils;
+	private Writer writer;
+	private Parser parser;
+	private Factory factory;
+	private UriBuilderFactory uriBuilder;
+
+	private AtomicInteger counter = new AtomicInteger();
+
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Required
+	public void setUtils(FilenameUtils utils) {
+		this.utils = utils;
+	}
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		this.factory = abdera.getFactory();
+		this.parser = abdera.getParser();
+		this.writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	@Required
+	// webapp
+	public void setUriBuilder(UriBuilderFactory uriBuilder) {
+		this.uriBuilder = uriBuilder;
+	}
+
+	private final Map<String, URL> endPoints = new HashMap<>();
+
+	@PostConstruct
+	void determinePorts() {
+		try {
+			MBeanServer mbs = getPlatformMBeanServer();
+			for (ObjectName obj : mbs.queryNames(new ObjectName(
+					"*:type=Connector,*"),
+					match(attr("protocol"), value("HTTP/1.1")))) {
+				String scheme = mbs.getAttribute(obj, "scheme").toString();
+				String port = obj.getKeyProperty("port");
+				endPoints.put(scheme, new URL(scheme + "://localhost:" + port));
+			}
+			getLog(getClass()).info(
+					"installed feed port publication mapping for "
+							+ endPoints.keySet());
+		} catch (Exception e) {
+			getLog(getClass()).error(
+					"failure in determining local port mapping", e);
+		}
+	}
+	
+	/**
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @return The URI of the feed
+	 */
+	public URI getFeedURI(TavernaRun run) {
+		return uriBuilder.getRunUriBuilder(run).path(FEED_URL_DIR).build();
+	}
+
+	@Nullable
+	public URL getLocalFeedBase(URI feedURI) {
+		if (feedURI == null)
+			return null;
+		return endPoints.get(feedURI.getScheme());
+	}
+
+	/**
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param id
+	 *            The ID of the entry.
+	 * @return The URI of the entry.
+	 */
+	public URI getEntryURI(TavernaRun run, String id) {
+		return uriBuilder.getRunUriBuilder(run)
+				.path(FEED_URL_DIR + "/{entryID}").build(id);
+	}
+
+	private Entry getEntryFromFile(File f) throws FilesystemAccessException {
+		long size = f.getSize();
+		if (size > MAX_ENTRY_SIZE)
+			throw new FilesystemAccessException("entry larger than 50kB");
+		byte[] contents = f.getContents(0, (int) size);
+		Document<Entry> doc = parser.parse(new ByteArrayInputStream(contents));
+		return doc.getRoot();
+	}
+
+	private void putEntryInFile(Directory dir, String name, Entry contents)
+			throws FilesystemAccessException, NoUpdateException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		try {
+			writer.writeTo(contents, baos);
+		} catch (IOException e) {
+			throw new NoUpdateException("failed to serialize the ATOM entry", e);
+		}
+		File f = dir.makeEmptyFile(support.getPrincipal(), name);
+		f.appendContents(baos.toByteArray());
+	}
+
+	private List<DirectoryEntry> listPossibleEntries(TavernaRun run)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		List<DirectoryEntry> entries = new ArrayList<>(utils.getDirectory(run,
+				FEED_DIR).getContentsByDate());
+		reverse(entries);
+		return entries;
+	}
+
+	private String getRunURL(TavernaRun run) {
+		return new IRI(uriBuilder.getRunUriBuilder(run).build()).toString();
+	}
+
+	/**
+	 * Get the interaction feed for a partciular run.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @return The Abdera feed descriptor.
+	 * @throws FilesystemAccessException
+	 *             If the feed directory can't be read for some reason.
+	 * @throws NoDirectoryEntryException
+	 *             If the feed directory doesn't exist or an entry is
+	 *             unexpectedly removed.
+	 */
+	public Feed getRunFeed(TavernaRun run) throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		URI feedURI = getFeedURI(run);
+		Feed feed = factory.newFeed();
+		feed.setTitle("Interactions for Taverna Run \"" + run.getName() + "\"");
+		feed.addLink(new IRI(feedURI).toString(), "self");
+		feed.addLink(getRunURL(run), "workflowrun");
+		boolean fetchedDate = false;
+		for (DirectoryEntry de : listPossibleEntries(run)) {
+			if (!(de instanceof File))
+				continue;
+			try {
+				Entry e = getEntryFromFile((File) de);
+				if (STRIP_CONTENTS)
+					e.setContentElement(null);
+				feed.addEntry(e);
+				if (fetchedDate)
+					continue;
+				Date last = e.getUpdated();
+				if (last == null)
+					last = e.getPublished();
+				if (last == null)
+					last = de.getModificationDate();
+				feed.setUpdated(last);
+				fetchedDate = true;
+			} catch (FilesystemAccessException e) {
+				// Can't do anything about it, so we'll just drop the entry.
+			}
+		}
+		return feed;
+	}
+
+	/**
+	 * Gets the contents of a particular feed entry.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entryID
+	 *            The identifier (from the path) of the entry to read.
+	 * @return The description of the entry.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be read or is too large.
+	 * @throws NoDirectoryEntryException
+	 *             If the entry can't be found.
+	 */
+	public Entry getRunFeedEntry(TavernaRun run, String entryID)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		File entryFile = utils.getFile(run, FEED_DIR + "/" + entryID + EXT);
+		return getEntryFromFile(entryFile);
+	}
+
+	/**
+	 * Given a partial feed entry, store a complete feed entry in the filesystem
+	 * for a particular run. Note that this does not permit update of an
+	 * existing entry; the entry is always created new.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entry
+	 *            The partial entry to store
+	 * @return A link to the entry.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be stored.
+	 * @throws NoDirectoryEntryException
+	 *             If the run is improperly configured.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to do the write.
+	 * @throws MalformedURLException
+	 *             If a generated URL is illegal (shouldn't happen).
+	 */
+	public Entry addRunFeedEntry(TavernaRun run, Entry entry)
+			throws FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		support.permitUpdate(run);
+		Date now = new Date();
+		entry.newId();
+		String localId = "entry_" + counter.incrementAndGet();
+		IRI selfLink = new IRI(getEntryURI(run, localId));
+		entry.addLink(selfLink.toString(), "self");
+		entry.addLink(getRunURL(run), "workflowrun");
+		entry.setUpdated(now);
+		entry.setPublished(now);
+		putEntryInFile(utils.getDirectory(run, FEED_DIR), localId + EXT, entry);
+		return getEntryFromFile(utils.getFile(run, FEED_DIR + "/" + localId
+				+ EXT));
+	}
+
+	/**
+	 * Deletes an entry from a feed.
+	 * 
+	 * @param run
+	 *            The workflow run that defines which feed we are operating on.
+	 * @param entryID
+	 *            The ID of the entry to delete.
+	 * @throws FilesystemAccessException
+	 *             If the entry can't be deleted
+	 * @throws NoDirectoryEntryException
+	 *             If the entry can't be found.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to modify the run's
+	 *             characteristics.
+	 */
+	public void removeRunFeedEntry(TavernaRun run, String entryID)
+			throws FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		support.permitUpdate(run);
+		utils.getFile(run, FEED_DIR + "/" + entryID + EXT).destroy();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
new file mode 100644
index 0000000..9efc30d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interaction/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the Atom feed implementation for interactions for a particular workflow run.
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.interaction;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
new file mode 100644
index 0000000..9a0a84e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Directory.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.io.PipedInputStream;
+import java.security.Principal;
+import java.util.Collection;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * Represents a directory that is the working directory of a workflow run, or a
+ * sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see File
+ */
+public interface Directory extends DirectoryEntry {
+	/**
+	 * @return A list of the contents of the directory.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	Collection<DirectoryEntry> getContents() throws FilesystemAccessException;
+
+	/**
+	 * @return A list of the contents of the directory, in guaranteed date
+	 *         order.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	Collection<DirectoryEntry> getContentsByDate()
+			throws FilesystemAccessException;
+
+	/**
+	 * @return The contents of the directory (and its sub-directories) as a zip.
+	 * @throws FilesystemAccessException
+	 *             If things go wrong.
+	 */
+	ZipStream getContentsAsZip() throws FilesystemAccessException;
+
+	/**
+	 * Creates a sub-directory of this directory.
+	 * 
+	 * @param actor
+	 *            Who this is being created by.
+	 * @param name
+	 *            The name of the sub-directory.
+	 * @return A handle to the newly-created directory.
+	 * @throws FilesystemAccessException
+	 *             If the name is the same as some existing entry in the
+	 *             directory, or if something else goes wrong during creation.
+	 */
+	Directory makeSubdirectory(Principal actor, String name)
+			throws FilesystemAccessException;
+
+	/**
+	 * Creates an empty file in this directory.
+	 * 
+	 * @param actor
+	 *            Who this is being created by.
+	 * @param name
+	 *            The name of the file to create.
+	 * @return A handle to the newly-created file.
+	 * @throws FilesystemAccessException
+	 *             If the name is the same as some existing entry in the
+	 *             directory, or if something else goes wrong during creation.
+	 */
+	File makeEmptyFile(Principal actor, String name)
+			throws FilesystemAccessException;
+
+	/**
+	 * A simple pipe that produces the zipped contents of a directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class ZipStream extends PipedInputStream {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
new file mode 100644
index 0000000..b098152
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/DirectoryEntry.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.util.Date;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * An entry in a {@link Directory} representing a file or sub-directory.
+ * 
+ * @author Donal Fellows
+ * @see Directory
+ * @see File
+ */
+public interface DirectoryEntry extends Comparable<DirectoryEntry> {
+	/**
+	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
+	 *         or contain the character "<tt>/</tt>".
+	 */
+	public String getName();
+
+	/**
+	 * @return The "full" name of the entry. This is computed relative to the
+	 *         workflow run's working directory. It may contain the "<tt>/</tt>"
+	 *         character.
+	 */
+	public String getFullName();
+
+	/**
+	 * @return The time that the entry was last modified.
+	 */
+	public Date getModificationDate();
+
+	/**
+	 * Destroy this directory entry, deleting the file or sub-directory. The
+	 * workflow run's working directory can never be manually destroyed.
+	 * 
+	 * @throws FilesystemAccessException
+	 *             If the destroy fails for some reason.
+	 */
+	public void destroy() throws FilesystemAccessException;
+	// TODO: Permissions (or decide not to do anything about them)
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
new file mode 100644
index 0000000..e4e6590
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/File.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * Represents a file in the working directory of a workflow instance run, or in
+ * some sub-directory of it.
+ * 
+ * @author Donal Fellows
+ * @see Directory
+ */
+public interface File extends DirectoryEntry {
+	/**
+	 * @param offset
+	 *            Where in the file to start reading.
+	 * @param length
+	 *            The length of file to read, or -1 to read to the end of the
+	 *            file.
+	 * @return The literal byte contents of the section of the file, or null if
+	 *         the section doesn't exist.
+	 * @throws FilesystemAccessException
+	 *             If the read of the file goes wrong.
+	 */
+	public byte[] getContents(int offset, int length)
+			throws FilesystemAccessException;
+
+	/**
+	 * Write the data to the file, totally replacing what was there before.
+	 * 
+	 * @param data
+	 *            The literal bytes that will form the new contents of the file.
+	 * @throws FilesystemAccessException
+	 *             If the write to the file goes wrong.
+	 */
+	public void setContents(byte[] data) throws FilesystemAccessException;
+
+	/**
+	 * Append the data to the file.
+	 * 
+	 * @param data
+	 *            The literal bytes that will be added on to the end of the
+	 *            file.
+	 * @throws FilesystemAccessException
+	 *             If the write to the file goes wrong.
+	 */
+	public void appendContents(byte[] data) throws FilesystemAccessException;
+
+	/**
+	 * @return The length of the file, in bytes.
+	 * @throws FilesystemAccessException
+	 *             If the read of the file size goes wrong.
+	 */
+	public long getSize() throws FilesystemAccessException;
+
+	/**
+	 * Asks for the argument file to be copied to this one.
+	 * 
+	 * @param from
+	 *            The source file.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	public void copy(File from) throws FilesystemAccessException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
new file mode 100644
index 0000000..31cb7cb
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Input.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+/**
+ * This represents the assignment of inputs to input ports of the workflow. Note
+ * that the <tt>file</tt> and <tt>value</tt> properties are never set at the
+ * same time.
+ * 
+ * @author Donal Fellows
+ */
+public interface Input {
+	/**
+	 * @return The file currently assigned to this input port, or <tt>null</tt>
+	 *         if no file is assigned.
+	 */
+	@Nullable
+	public String getFile();
+
+	/**
+	 * @return The name of this input port. This may not be changed.
+	 */
+	@Nonnull
+	public String getName();
+
+	/**
+	 * @return The value currently assigned to this input port, or <tt>null</tt>
+	 *         if no value is assigned.
+	 */
+	@Nullable
+	public String getValue();
+
+	/**
+	 * @return The delimiter for the input port, or <tt>null</tt> if the value
+	 *         is not to be split.
+	 */
+	@Nullable
+	public String getDelimiter();
+
+	/**
+	 * Sets the file to use for this input. This overrides the use of the
+	 * previous file and any set value.
+	 * 
+	 * @param file
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws FilesystemAccessException
+	 *             If the filename is invalid.
+	 * @throws BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	public void setFile(String file) throws FilesystemAccessException,
+			BadStateChangeException;
+
+	/**
+	 * Sets the value to use for this input. This overrides the use of the
+	 * previous value and any set file.
+	 * 
+	 * @param value
+	 *            The value to use.
+	 * @throws BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	public void setValue(String value) throws BadStateChangeException;
+
+	/**
+	 * Sets (or clears) the delimiter for the input port.
+	 * 
+	 * @param delimiter
+	 *            The delimiter character, or <tt>null</tt> if the value is not
+	 *            to be split.
+	 * @throws BadStateChangeException
+	 *             If the run isn't in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	@Nullable
+	public void setDelimiter(String delimiter) throws BadStateChangeException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
new file mode 100644
index 0000000..d7998bc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Listener.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+import org.taverna.server.master.exceptions.NoListenerException;
+
+/**
+ * An event listener that can be attached to a {@link TavernaRun}.
+ * 
+ * @author Donal Fellows
+ */
+public interface Listener {
+	/**
+	 * @return The name of the listener.
+	 */
+	public String getName();
+
+	/**
+	 * @return The type of the listener.
+	 */
+	public String getType();
+
+	/**
+	 * @return The configuration document for the listener.
+	 */
+	public String getConfiguration();
+
+	/**
+	 * @return The supported properties of the listener.
+	 */
+	public String[] listProperties();
+
+	/**
+	 * Get the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to read.
+	 * @return The value of the property.
+	 * @throws NoListenerException
+	 *             If no property with that name exists.
+	 */
+	public String getProperty(String propName) throws NoListenerException;
+
+	/**
+	 * Set the value of a particular property, which should be listed in the
+	 * {@link #listProperties()} method.
+	 * 
+	 * @param propName
+	 *            The name of the property to write.
+	 * @param value
+	 *            The value to set the property to.
+	 * @throws NoListenerException
+	 *             If no property with that name exists.
+	 * @throws BadPropertyValueException
+	 *             If the value of the property is bad (e.g., wrong syntax).
+	 */
+	public void setProperty(String propName, String value)
+			throws NoListenerException, BadPropertyValueException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
new file mode 100644
index 0000000..37b104e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/LocalIdentityMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * This interface describes how to map from the identity understood by the
+ * webapp to the identity understood by the local execution system.
+ * 
+ * @author Donal Fellows
+ */
+public interface LocalIdentityMapper {
+	/**
+	 * Given a user's identity, get the local identity to use for executing
+	 * their workflows. Note that it is assumed that there will never be a
+	 * failure from this interface; it is <i>not</i> a security policy
+	 * decision or enforcement point.
+	 * 
+	 * @param user
+	 *            An identity token.
+	 * @return A user name, which must be defined in the context that workflows
+	 *         will be running in.
+	 */
+	public String getUsernameForPrincipal(UsernamePrincipal user);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
new file mode 100644
index 0000000..37dbf2c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/MessageDispatcher.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import javax.annotation.Nonnull;
+
+/**
+ * The interface supported by all notification message dispatchers.
+ * @author Donal Fellows
+ */
+public interface MessageDispatcher {
+	/**
+	 * @return Whether this message dispatcher is actually available (fully
+	 *         configured, etc.)
+	 */
+	boolean isAvailable();
+
+	/**
+	 * @return The name of this dispatcher, which must match the protocol
+	 *         supported by it (for a non-universal dispatcher) and the name of
+	 *         the message generator used to produce the message.
+	 */
+	String getName();
+
+	/**
+	 * Dispatch a message to a recipient.
+	 * 
+	 * @param originator
+	 *            The workflow run that produced the message.
+	 * @param messageSubject
+	 *            The subject of the message to send.
+	 * @param messageContent
+	 *            The plain-text content of the message to send.
+	 * @param targetParameter
+	 *            A description of where it is to go.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	void dispatch(@Nonnull TavernaRun originator,
+			@Nonnull String messageSubject, @Nonnull String messageContent,
+			@Nonnull String targetParameter) throws Exception;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
new file mode 100644
index 0000000..f57fe71
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/Policy.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Simple policy interface.
+ * 
+ * @author Donal Fellows
+ */
+public interface Policy {
+	/**
+	 * @return The maximum number of runs that the system can support.
+	 */
+	int getMaxRuns();
+
+	/**
+	 * Get the limit on the number of runs for this user.
+	 * 
+	 * @param user
+	 *            Who to get the limit for
+	 * @return The maximum number of runs for this user, or <tt>null</tt> if no
+	 *         per-user limit is imposed and only system-wide limits are to be
+	 *         enforced.
+	 */
+	Integer getMaxRuns(UsernamePrincipal user);
+
+	/**
+	 * Test whether the user can create an instance of the given workflow.
+	 * 
+	 * @param user
+	 *            Who wants to do the creation.
+	 * @param workflow
+	 *            The workflow they wish to instantiate.
+	 * @throws NoCreateException
+	 *             If they may not instantiate it.
+	 */
+	void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException;
+
+	/**
+	 * Test whether the user can destroy a workflow instance run or manipulate
+	 * its expiry date.
+	 * 
+	 * @param user
+	 *            Who wants to do the deletion.
+	 * @param run
+	 *            What they want to delete.
+	 * @throws NoDestroyException
+	 *             If they may not destroy it.
+	 */
+	void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException;
+
+	/**
+	 * Return whether the user has access to a particular workflow run.
+	 * <b>Note</b> that this does not throw any exceptions!
+	 * 
+	 * @param user
+	 *            Who wants to read the workflow's state.
+	 * @param run
+	 *            What do they want to read from.
+	 * @return Whether they can read it. Note that this check is always applied
+	 *         before testing whether the workflow can be updated or deleted by
+	 *         the user.
+	 */
+	boolean permitAccess(UsernamePrincipal user, TavernaRun run);
+
+	/**
+	 * Test whether the user can modify a workflow run (other than for its
+	 * expiry date).
+	 * 
+	 * @param user
+	 *            Who wants to do the modification.
+	 * @param run
+	 *            What they want to modify.
+	 * @throws NoUpdateException
+	 *             If they may not modify it.
+	 */
+	void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException;
+
+	/**
+	 * Get the URIs of the workflows that the given user may execute.
+	 * 
+	 * @param user
+	 *            Who are we finding out on behalf of.
+	 * @return A list of workflow URIs that they may instantiate, or
+	 *         <tt>null</tt> if any workflow may be submitted.
+	 */
+	List<URI> listPermittedWorkflowURIs(UsernamePrincipal user);
+
+	/**
+	 * @return The maximum number of {@linkplain Status#Operating operating}
+	 *         runs that the system can support.
+	 */
+	int getOperatingLimit();
+
+	/**
+	 * Set the URIs of the workflows that the given user may execute.
+	 * 
+	 * @param user
+	 *            Who are we finding out on behalf of.
+	 * @param permitted
+	 *            A list of workflow URIs that they may instantiate.
+	 */
+	void setPermittedWorkflowURIs(UsernamePrincipal user, List<URI> permitted);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
new file mode 100644
index 0000000..b5e84c5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/RunStore.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.util.Map;
+
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Interface to the mechanism that looks after the mapping of names to runs.
+ * Instances of this class may also be responsible for enforcing timely cleanup
+ * of expired workflows.
+ * 
+ * @author Donal Fellows.
+ */
+public interface RunStore {
+	/**
+	 * Obtain the workflow run for a given user and name.
+	 * 
+	 * @param user
+	 *            Who wants to do the lookup.
+	 * @param p
+	 *            The general policy system context.
+	 * @param uuid
+	 *            The handle for the run.
+	 * @return The workflow instance run.
+	 * @throws UnknownRunException
+	 *             If the lookup fails (either because it does not exist or
+	 *             because it is not permitted for the user by the policy).
+	 */
+	TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException;
+
+	/**
+	 * Obtain the named workflow run.
+	 * 
+	 * @param uuid
+	 *            The handle for the run.
+	 * @return The workflow instance run.
+	 * @throws UnknownRunException
+	 *             If the lookup fails (either because it does not exist or
+	 *             because it is not permitted for the user by the policy).
+	 */
+	public TavernaRun getRun(String uuid) throws UnknownRunException;
+
+	/**
+	 * List the runs that a particular user may access.
+	 * 
+	 * @param user
+	 *            Who wants to do the lookup, or <code>null</code> if it is
+	 *            being done "by the system" when the full mapping should be
+	 *            returned.
+	 * @param p
+	 *            The general policy system context.
+	 * @return A mapping from run names to run instances.
+	 */
+	Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p);
+
+	/**
+	 * Adds a workflow instance run to the store. Note that this operation is
+	 * <i>not</i> expected to be security-checked; that is the callers'
+	 * responsibility.
+	 * 
+	 * @param run
+	 *            The run itself.
+	 * @return The name of the run.
+	 */
+	String registerRun(TavernaRun run);
+
+	/**
+	 * Removes a run from the store. Note that this operation is <i>not</i>
+	 * expected to be security-checked; that is the callers' responsibility.
+	 * 
+	 * @param uuid
+	 *            The name of the run.
+	 */
+	void unregisterRun(String uuid);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
new file mode 100644
index 0000000..902c4d0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/SecurityContextFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.io.Serializable;
+
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * How to create instances of a security context.
+ * 
+ * @author Donal Fellows
+ */
+public interface SecurityContextFactory extends Serializable {
+	/**
+	 * Creates a security context.
+	 * 
+	 * @param run
+	 *            Handle to remote run. Allows the security context to know how
+	 *            to apply itself to the workflow run.
+	 * @param owner
+	 *            The identity of the owner of the workflow run.
+	 * @return The security context.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	TavernaSecurityContext create(TavernaRun run, UsernamePrincipal owner)
+			throws Exception;
+}


[30/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/jquery-1.8.0.min.js
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/jquery-1.8.0.min.js b/server-webapp/src/main/resources/static/jquery-1.8.0.min.js
deleted file mode 100644
index f121291..0000000
--- a/server-webapp/src/main/resources/static/jquery-1.8.0.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jQuery v@1.8.0 jquery.com | jquery.org/license */
-(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(
 a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="scri
 pt"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bX(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bV.length;while(e--){b=bV[e]+c;if(b in a)return b}return d}function bY(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function bZ(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bY(c)&&(e[f]=p._data(c,"olddisplay",cb(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b$(a,b,c){
 var d=bO.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function b_(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bU[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bU[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bU[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bU[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bU[e]+"Width"))||0));return f}function ca(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bP.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+b_(a,b,c||(f?"border":"content"),e)+"px"}function cb(a){if(bR[a])return bR[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createEle
 ment)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bR[a]=c,c}function ch(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||cd.test(a)?d(a,e):ch(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ch(a+"["+e+"]",b[e],c,d);else d(a,b)}function cy(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cz(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cu;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cz(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cz(a,c,d,e,"*",g)),h}function cA(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c
 )c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cB(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cC(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"succe
 ss",data:b}}function cK(){try{return new a.XMLHttpRequest}catch(b){}}function cL(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cT(){return setTimeout(function(){cM=b},0),cM=p.now()}function cU(a,b){p.each(b,function(b,c){var d=(cS[b]||[]).concat(cS["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cV(a,b,c){var d,e=0,f=0,g=cR.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cM||cT(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cM||cT(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.t
 weens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cW(k,j.opts.specialEasing);for(;e<g;e++){d=cR[e].call(j,a,k,j.opts);if(d)return d}return cU(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cW(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cX(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bY(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||
 "width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cb(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cO.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cY(a,b,c,d,e){return new cY.prototype.init(a,b,c,d,e)}function cZ(a,b){var c,d={height:a},e=0;for(;e<4;e+=2-b)c=bU[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d
 .width=a),d}function c_(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=r.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:fu
 nction(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return
  d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)contin
 ue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.p
 rototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("In
 valid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:functi
 on(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if
 (c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete"||e.readyState!=="loading"&&e.addEventListener)setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;
 h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){p.isFunction(c)&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callba
 cks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.n
 otifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkO
 n:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).c
 loneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display
 :block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/^(?:\{.*\}|\[.*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQu
 ery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||++p.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];
 if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")===0&&(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,
 c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.shift(),e=p._queueHooks(a,b),f=function(){p.dequeue(a,b)};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),delete e.stop,d.call(a,f,e)),!c.length&&e&&e.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue
 :function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)(d=p._data(g[h],a+"queueHooks"))&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.pro
 p,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>-1)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleCla
 ss:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.va
 l()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;
 if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b
 ,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:
 !0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selec
 tedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,argu
 ments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(
 ".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join(
 "\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[
 m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=[].slice.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click")){g=p(this),g.context=this;for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){i={},k=[],g[0]=f;for(d=0;d<q;d++)l=o[d],m=l.selector,i[m]===b&&(i[m]=g.is(m)),i[m]&&k.push(l);k.length&&u.push({elem:f,matches:k})}}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){j=u[d],c.currentTarget=j.elem;for(e=0;e<j.matches.length&&!c.isImmediatePropagationStopped();e++){l=j.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=
 l,h=((p.event.special[l.origType]||{}).handle||l.handler).apply(j.elem,r),h!==b&&(c.result=h,h===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&
 &g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{ready:{setup:p.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventList
 ener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStop
 ped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(t
 his.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simul
 ate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(t
 his,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown m
 ouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bd(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)Z(a,b[e],c,d)}function be(a,b,c,d,e,f){var g,h=$.setFilters[b.toLowerCase()];return h||Z.error(b),(a||!(g=e))&&bd(a||"*",d,g=[],e),g.length>0?h(g,c,f):[]}function bf(a,c,d,e,f){var g,h,i,j,k,l,m,n,p=0,q=f.length,s=L.POS,t=new RegExp("^"+s.source+"(?!"+r+")","i"),u=function(){var a=1,c=arguments.length-2;for(;a<c;a++)arguments[a]===b&&(g[a]=b)};for(;p<q;p++){s.exec(""),a=f[p],j=[],i=0,k=e;while(g=s.exec(a)){n=s.lastIndex=g.index+g[0].length;if(n>i){m=a.slice(i,g.index),i=n,l=[c],B.test(m)&&(k&&(l=k),k=e);if(h=H.test(m))m=m.slice(0,-5).replace(B,"$&*");g.length>1&&g[0]
 .replace(t,u),k=be(m,g[1],g[2],l,k,h)}}k?(j=j.concat(k),(m=a.slice(i))&&m!==")"?B.test(m)?bd(m,j,d,e):Z(m,c,d,e?e.concat(k):k):o.apply(d,j)):Z(a,c,d,e)}return q===1?d:Z.uniqueSort(d)}function bg(a,b,c){var d,e,f,g=[],i=0,j=D.exec(a),k=!j.pop()&&!j.pop(),l=k&&a.match(C)||[""],m=$.preFilter,n=$.filter,o=!c&&b!==h;for(;(e=l[i])!=null&&k;i++){g.push(d=[]),o&&(e=" "+e);while(e){k=!1;if(j=B.exec(e))e=e.slice(j[0].length),k=d.push({part:j.pop().replace(A," "),captures:j});for(f in n)(j=L[f].exec(e))&&(!m[f]||(j=m[f](j,b,c)))&&(e=e.slice(j.shift().length),k=d.push({part:f,captures:j}));if(!k)break}}return k||Z.error(a),g}function bh(a,b,e){var f=b.dir,g=m++;return a||(a=function(a){return a===e}),b.first?function(b,c){while(b=b[f])if(b.nodeType===1)return a(b,c)&&b}:function(b,e){var h,i=g+"."+d,j=i+"."+c;while(b=b[f])if(b.nodeType===1){if((h=b[q])===j)return b.sizset;if(typeof h=="string"&&h.indexOf(i)===0){if(b.sizset)return b}else{b[q]=j;if(a(b,e))return b.sizset=!0,b;b.sizset=!1}}}}func
 tion bi(a,b){return a?function(c,d){var e=b(c,d);return e&&a(e===!0?c:e,d)}:b}function bj(a,b,c){var d,e,f=0;for(;d=a[f];f++)$.relative[d.part]?e=bh(e,$.relative[d.part],b):(d.captures.push(b,c),e=bi(e,$.filter[d.part].apply(null,d.captures)));return e}function bk(a){return function(b,c){var d,e=0;for(;d=a[e];e++)if(d(b,c))return!0;return!1}}var c,d,e,f,g,h=a.document,i=h.documentElement,j="undefined",k=!1,l=!0,m=0,n=[].slice,o=[].push,q=("sizcache"+Math.random()).replace(".",""),r="[\\x20\\t\\r\\n\\f]",s="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",t=s.replace("w","w#"),u="([*^$|!~]?=)",v="\\["+r+"*("+s+")"+r+"*(?:"+u+r+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+t+")|)|)"+r+"*\\]",w=":("+s+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",x=":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",y=r+"*([\\x20\\t\\r\\n\\f>+~])"+r+"*",z="(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|"+v+"|"+w.replace(2,7)+"|[^\\\\(),])+",A=new RegExp("^"+r+"+|
 ((?:^|[^\\\\])(?:\\\\.)*)"+r+"+$","g"),B=new RegExp("^"+y),C=new RegExp(z+"?(?="+r+"*,|$)","g"),D=new RegExp("^(?:(?!,)(?:(?:^|,)"+r+"*"+z+")*?|"+r+"*(.*?))(\\)|$)"),E=new RegExp(z.slice(19,-6)+"\\x20\\t\\r\\n\\f>+~])+|"+y,"g"),F=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,G=/[\x20\t\r\n\f]*[+~]/,H=/:not\($/,I=/h\d/i,J=/input|select|textarea|button/i,K=/\\(?!\\)/g,L={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),NAME:new RegExp("^\\[name=['\"]?("+s+")['\"]?\\]"),TAG:new RegExp("^("+s.replace("[-","[-\\*")+")"),ATTR:new RegExp("^"+v),PSEUDO:new RegExp("^"+w),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+r+"*(even|odd|(([+-]|)(\\d*)n|)"+r+"*(?:([+-]|)"+r+"*(\\d+)|))"+r+"*\\)|)","i"),POS:new RegExp(x,"ig"),needsContext:new RegExp("^"+r+"*[>+~]|"+x,"i")},M={},N=[],O={},P=[],Q=function(a){return a.sizzleFilter=!0,a},R=function(a){return function(b){return b.nodeName.toLowerCase()==="input"&&b.type===a}},S=function(a){return function(b){var c=b.nodeName.toLowerCase();return
 (c==="input"||c==="button")&&b.type===a}},T=function(a){var b=!1,c=h.createElement("div");try{b=a(c)}catch(d){}return c=null,b},U=T(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),V=T(function(a){a.id=q+0,a.innerHTML="<a name='"+q+"'></a><div name='"+q+"'></div>",i.insertBefore(a,i.firstChild);var b=h.getElementsByName&&h.getElementsByName(q).length===2+h.getElementsByName(q+0).length;return g=!h.getElementById(q),i.removeChild(a),b}),W=T(function(a){return a.appendChild(h.createComment("")),a.getElementsByTagName("*").length===0}),X=T(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==j&&a.firstChild.getAttribute("href")==="#"}),Y=T(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||a.getElementsByClassName("e").length===0?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length!=
 =1)}),Z=function(a,b,c,d){c=c||[],b=b||h;var e,f,g,i,j=b.nodeType;if(j!==1&&j!==9)return[];if(!a||typeof a!="string")return c;g=ba(b);if(!g&&!d)if(e=F.exec(a))if(i=e[1]){if(j===9){f=b.getElementById(i);if(!f||!f.parentNode)return c;if(f.id===i)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(i))&&bb(b,f)&&f.id===i)return c.push(f),c}else{if(e[2])return o.apply(c,n.call(b.getElementsByTagName(a),0)),c;if((i=e[3])&&Y&&b.getElementsByClassName)return o.apply(c,n.call(b.getElementsByClassName(i),0)),c}return bm(a,b,c,d,g)},$=Z.selectors={cacheLength:50,match:L,order:["ID","TAG"],attrHandle:{},createPseudo:Q,find:{ID:g?function(a,b,c){if(typeof b.getElementById!==j&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==j&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==j&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:W?function(a,b){if(typeof b.getElementsByTagName!==j)retur
 n b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(K,""),a[3]=(a[4]||a[5]||"").replace(K,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||Z.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&Z.error(a[0]),a},PSEUDO:function(a){var b,c=a[4];return L.CHILD.test(a[0])?null:(c&&(b=D.exec(c))&&b.pop()&&(a[0]=a[0].slice(0,b[0].length-c.length-1),c=b[0].slice(0,-1)),a.splice(2,3,c||a[3]),a)}},filter:{ID:g?function(a){return a=a.replace(K,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(K,""),function(b){var c=typeof b.getAttributeNode!==j
 &&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(K,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=M[a];return b||(b=M[a]=new RegExp("(^|"+r+")"+a+"("+r+"|$)"),N.push(a),N.length>$.cacheLength&&delete M[N.shift()]),function(a){return b.test(a.className||typeof a.getAttribute!==j&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=Z.attr(d,a),f=e+"";if(e==null)return b==="!=";switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&f.indexOf(c)===0;case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return Z.attr(b,a)!=null}},CHILD:function(a,b,c,d){if(a==="nth"){var e=m++;return function(a){var b,f,g=0,h=a;if(c===1&&d===0)return!0;b=a.parentNode;if(b&&(b[q]!==e||!a.sizset)){for(
 h=b.firstChild;h;h=h.nextSibling)if(h.nodeType===1){h.sizset=++g;if(h===a)break}b[q]=e}return f=a.sizset-d,c===0?f===0:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e=$.pseudos[a]||$.pseudos[a.toLowerCase()];return e||Z.error("unsupported pseudo: "+a),e.sizzleFilter?e(b,c,d):e}},pseudos:{not:Q(function(a,b,c){var d=bl(a.replace(A,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!$.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.no
 deType)===3||b===4)return!1;a=a.nextSibling}return!0},contains:Q(function(a){return function(b){return(b.textContent||b.innerText||bc(b)).indexOf(a)>-1}}),has:Q(function(a){return function(b){return Z(a,b).length>0}}),header:function(a){return I.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:R("radio"),checkbox:R("checkbox"),file:R("file"),password:R("password"),image:R("image"),submit:S("submit"),reset:S("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return J.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(
 a,b,c){var d=[],e=c?1:0,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},odd:function(a,b,c){var d=[],e=c?0:1,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}};$.setFilters.nth=$.setFilters.eq,$.filters=$.pseudos,X||($.attrHandle={href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}}),V&&($.order.push("NAME"),$.find.NAME=function(a,b){if(typeof b.getElementsByName!==j)return b.getElementsByName(a)}),Y&&($.order.splice(1,0,"CLASS"),$.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!==j&&!c)return b.getElementsByClassName(a)});try{n.call(i.childNodes,0)[0].nodeType}catch(_){n=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}var ba=Z.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},bb=Z.contains=i.compa
 reDocumentPosition?function(a,b){return!!(a.compareDocumentPosition(b)&16)}:i.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc=Z.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=bc(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=bc(b);return c};Z.attr=function(a,b){var c,d=ba(a);return d||(b=b.toLowerCase()),$.attrHandle[b]?$.attrHandle[b](a):U||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},Z.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},[0,0].sort(function(){return l=0}),i.compareDocumentPosition?e=function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPos
 ition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:(e=function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],g=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return f(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)g.unshift(j),j=j.parentNode;c=e.length,d=g.length;for(var l=0;l<c&&l<d;l++)if(e[l]!==g[l])return f(e[l],g[l]);return l===c?f(a,g[l],-1):f(e[l],b,1)},f=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),Z.uniqueSort=function(a){var b,c=1;if(e){k=l,a.sort(e);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1)}return a};var bl=Z.compile=function(a,b,c){var d,e,f,g=O[a];if(g&&g.context===b)return g;e=bg(a,b,c);for(f=0;d=e[f];f++)e[f]=bj(d,b,c);return g=O[a]=bk(e),g.context=b,g.runs=g.dirruns=0,P.push(a),P.length>$.cacheLength&&delete O[P.shift()],g};Z.matches=function(a,b){return Z(a,null,null,b)},Z.matchesSel
 ector=function(a,b){return Z(b,null,null,[a]).length>0};var bm=function(a,b,e,f,g){a=a.replace(A,"$1");var h,i,j,k,l,m,p,q,r,s=a.match(C),t=a.match(E),u=b.nodeType;if(L.POS.test(a))return bf(a,b,e,f,s);if(f)h=n.call(f,0);else if(s&&s.length===1){if(t.length>1&&u===9&&!g&&(s=L.ID.exec(t[0]))){b=$.find.ID(s[1],b,g)[0];if(!b)return e;a=a.slice(t.shift().length)}q=(s=G.exec(t[0]))&&!s.index&&b.parentNode||b,r=t.pop(),m=r.split(":not")[0];for(j=0,k=$.order.length;j<k;j++){p=$.order[j];if(s=L[p].exec(m)){h=$.find[p]((s[1]||"").replace(K,""),q,g);if(h==null)continue;m===r&&(a=a.slice(0,a.length-r.length)+m.replace(L[p],""),a||o.apply(e,n.call(h,0)));break}}}if(a){i=bl(a,b,g),d=i.dirruns++,h==null&&(h=$.find.TAG("*",G.test(a)&&b.parentNode||b));for(j=0;l=h[j];j++)c=i.runs++,i(l,b)&&e.push(l)}return e};h.querySelectorAll&&function(){var a,b=bm,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=i.matchesSelector||i.mozMatchesSelector||i.webkitMatchesSelector||i.o
 MatchesSelector||i.msMatchesSelector;T(function(a){a.innerHTML="<select><option selected></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+r+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),T(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+r+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),bm=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a)))if(d.nodeType===9)try{return o.apply(f,n.call(d.querySelectorAll(a),0)),f}catch(i){}else if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){var j=d.getAttribute("id"),k=j||q,l=G.test(a)&&d.parentNode||d;j?k=k.replace(c,"\\$&"):d.setAttribute("id",k);try{return o.apply(f,n.call(l.querySelectorAll(a.replace(C,"[id='"+k+"'] $&")),0)),f}catch(i){}finally{j||d.removeAttribute("id")}}return b
 (a,d,f,g,h)},g&&(T(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push($.match.PSEUDO)}catch(c){}}),f=new RegExp(f.join("|")),Z.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!ba(b)&&!f.test(c)&&(!e||!e.test(c)))try{var h=g.call(b,c);if(h||a||b.document&&b.document.nodeType!==11)return h}catch(i){}return Z(c,null,null,[b]).length>0})}(),Z.attr=p.attr,p.find=Z,p.expr=Z.selectors,p.expr[":"]=p.expr.pseudos,p.unique=Z.uniqueSort,p.text=Z.getText,p.isXMLDoc=Z.isXML,p.contains=Z.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice
 (e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.
 merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.
 map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new Reg
 Exp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[
 0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(
 a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nod
 eType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function()
 {p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=(c[0]||c).ownerDocument||c[0]||c,typeof c.createDocumentFragment=="undefined"&&(c=e),a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p
 .fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return 
 d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=0,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(g=b===e&&bA;(h=a[s])!=null;s++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{g=g||bk(b),l=l||g.appendChild(b.createElement("div")),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(f=n.length-1;f>=0;--f)p.nodeName(n[f],"tbody")&&!n[f].childNodes.length&&n[f].parentNode.removeChild(n[f])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l=g.lastChild}h.nodeType?t.push(h):t=p.merge(t,h)}l&&(g.removeChild(l),h=l=g=null);if(!p.support.appendChecked)for(s=0;(h=t[s])!=null;s++)p.nodeName(h,"input")?bG(h):type
 of h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(s=0;(h=t[s])!=null;s++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[s+1,0].concat(r)),s+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(ms
 ie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^margin/,bO=new RegExp("^("+q+")(.*)$","i"),bP=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bQ=new RegExp("^([-+])=("+q+")","i"),bR={},bS={position:"absolute",visibility:"hidden",display:"block"},bT={letterSpacing:0,fontWeight:400,lineHeight:1},bU=["Top","Right","Bottom","Left"],bV=["Webkit","O","Moz","ms"],bW=p.fn.toggle;p.fn.extend({css:funct
 ion(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return bZ(this,!0)},hide:function(){return bZ(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bW.apply(this,arguments):this.each(function(){(c?a:bY(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bX(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bQ.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&is
 NaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bX(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bT&&(f=bT[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(a,b){var c,d,e,f,g=getComputedStyle(a,null),h=a.style;return g&&(c=g[b],c===""&&!p.contains(a.ownerDocument.documentElement,a)&&(c=p.style(a,b)),bP.test(c)&&bN.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=c,c=g.width,h.width=d,h.minWidth=e,h.maxWidth=f)),c}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bP.test(e)&&!bM.te
 st(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0||bH(a,"display")!=="none"?ca(a,b,d):p.swap(a,bS,function(){return ca(a,b,d)})},set:function(a,c,d){return b$(a,c,d?b_(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarg
 inRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bP.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bU[d]+b]=e[d]||e[d-2]||e[0];return f}},bN.test(a)||(p.cssHooks[a+b].set=b$)});var cc=/%20/g,cd=/\[\]$/,ce=/\r?\n/g,cf=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,cg=/^(?:select|t
 extarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||cg.test(this.nodeName)||cf.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(ce,"\r\n")}}):{name:b.name,value:c.replace(ce,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ch(d,a[d],c,f);return e.join("&").replace(cc,"+")};var ci,cj,ck=/#.*$/,cl=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cm=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,cn=/^(?:GET|HEAD)$/
 ,co=/^\/\//,cp=/\?/,cq=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cr=/([?&])_=[^&]*/,cs=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,ct=p.fn.load,cu={},cv={},cw=["*/"]+["*"];try{ci=f.href}catch(cx){ci=e.createElement("a"),ci.href="",ci=ci.href}cj=cs.exec(ci.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&ct)return ct.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cq,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({ty
 pe:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cA(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cA(a,b),a},ajaxSettings:{url:ci,isLocal:cm.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cw},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cy(cu),ajaxTransport:cy(cv),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cB(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHea
 der("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cC(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=""+(c||y),k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cl.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return
  c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(ck,"").replace(co,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=cs.exec(l.url.toLowerCase()),l.crossDomain=!(!i||i[1]==cj[1]&&i[2]==cj[2]&&(i[3]||(i[1]==="http:"?80:443))==(cj[3]||(cj[1]==="http:"?80:443)))),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cz(cu,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!cn.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cp.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cr,"$1_="+z);l.url=A+(A===
 l.url?(cp.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cw+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cz(cv,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cD=[],cE=/\?/,cF=/(=)\?(?=&|$)|\?\?/,cG=p.now();p.ajaxSetup({j
 sonp:"callback",jsonpCallback:function(){var a=cD.pop()||p.expando+"_"+cG++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cF.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cF.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cF,"$1"+f):m?c.data=i.replace(cF,"$1"+f):k&&(c.url+=(cE.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cD.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":fu
 nction(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cH,cI=a.ActiveXObject?function(){for(var a in cH)cH[a](0,1)}:!1,cJ=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cK()||cL()}:cK,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){v
 ar d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cI&&delete cH[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cJ,cI&&(cH||(cH={},p(a).unload(cI)),cH[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});
 var cM,cN,cO=/^(?:toggle|show|hide)$/,cP=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cQ=/queueHooks$/,cR=[cX],cS={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=cP.exec(b),h=f.cur(),i=+h||0,j=1;if(g){c=+g[2],d=g[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&i){i=p.css(f.elem,a,!0)||c||1;do e=j=j||".5",i=i/j,p.style(f.elem,a,i+d),j=f.cur()/h;while(j!==1&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};p.Animation=p.extend(cV,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cS[c]=cS[c]||[],cS[c].unshift(b)},prefilter:function(a,b){b?cR.unshift(a):cR.push(a)}}),p.Tween=cY,cY.prototype={constructor:cY,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cY.propHooks[this.prop];return a&&a.get?a.get(this):cY.propHooks._default.get(this)},run:function(a){var b,c=cY.prop
 Hooks[this.prop];return this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration),this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cY.propHooks._default.set(this),this}},cY.prototype.init.prototype=cY.prototype,cY.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cY.propHooks.scrollTop=cY.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,argum
 ents):this.animate(cZ(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bY).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cV(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cQ.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:cZ("show"),slideUp:cZ("hide"),slideToggle:cZ("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.a
 nimate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duratio

<TRUNCATED>

[03/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png
new file mode 100644
index 0000000..c664c51
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png
new file mode 100644
index 0000000..6aed97a
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png
new file mode 100644
index 0000000..43ba34e
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png
new file mode 100644
index 0000000..68306d1
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png b/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png
new file mode 100644
index 0000000..f567c28
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png b/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png
new file mode 100644
index 0000000..5c5494f
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png b/taverna-server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png
new file mode 100644
index 0000000..9a46d19
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png b/taverna-server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png
new file mode 100644
index 0000000..f811f30
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png b/taverna-server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png
new file mode 100644
index 0000000..755fe99
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png b/taverna-server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png
new file mode 100644
index 0000000..98705f9
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png b/taverna-server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png
new file mode 100644
index 0000000..3f67eca
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png b/taverna-server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png
new file mode 100644
index 0000000..de76ce2
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png b/taverna-server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png
new file mode 100644
index 0000000..42f8f99
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/version.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/version.properties b/taverna-server-webapp/src/main/resources/version.properties
new file mode 100644
index 0000000..7ddb7d3
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/version.properties
@@ -0,0 +1,5 @@
+# What is the version of the server? Bind this in automatically.
+tavernaserver.version=${project.version}
+tavernaserver.revision.describe=${git.commit.id.describe}
+tavernaserver.branch=${git.branch}
+tavernaserver.timestamp=${git.build.time}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/welcome.html
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/welcome.html b/taverna-server-webapp/src/main/resources/welcome.html
new file mode 100644
index 0000000..f80da4a
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/welcome.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
+<title>Taverna Server %{VERSION}</title>
+</head>
+<body>
+<h1>Taverna Server %{VERSION}</h1>
+<div style="text-align;center">
+	<p>
+		<i>Note that this is a pre-release version. Significant known
+			issues remain open and it is not guaranteed that the service API
+			will be stable.</i>
+	</p>
+</div>
+<p>For a full list of operations, see the <a
+    href="%{BASEURL}/services">service listing</a> generated by Apache
+CXF, which indicates where to access the WSDL and WADL descriptions of
+the T2Server interface.</p>
+<p>What follows below is a simple guide to using the server. It does
+<i>not</i> cover all the features; a much more extensive guide is available on
+<a href="http://www.mygrid.org.uk/dev/wiki/display/taverna/Taverna+Server+2.4"
+>the myGrid website</a>.</p>
+<h2>5 Minute Guide to Using the REST API</h2>
+<p>Taverna Server %{VERSION} supports both REST and SOAP APIs; you may use either API
+to access the service and any of the workflow runs hosted by the service. This
+simple guide just discusses the REST API.</p>
+<ol>
+  <li>
+  <p>The client starts by creating a workflow run. This is done by POSTing a
+  T2flow document to the service at the address <tt>%{BASEURL}/rest/runs</tt>
+  with the content type <tt>application/vnd.taverna.t2flow+xml</tt>.</p>
+  <p>The result of the POST is an <tt>HTTP 201 Created</tt> that gives the
+  location of the created run (in a <tt>Location</tt> header),
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b></tt> (where <tt><b>UUID</b></tt> is a
+  unique string that identifies the particular run; this is also the name of
+  the run that you would use in the SOAP interface). Note that the run is not
+  yet actually doing anything.</p>
+  </li>
+  <li>
+  <p>Next, you need to set up the inputs to the workflow ports. To set the
+  input port, <tt><b>FOO</b></tt>, to have the value <tt><b>BAR</b></tt>, you
+  would PUT a message like this to the URI
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/input/input/<b>FOO</b></tt>
+  </p>
+  <blockquote><pre>&lt;t2sr:runInput xmlns:t2sr=&quot;http://ns.taverna.org.uk/2010/xml/server/rest/&quot;&gt;
+    &lt;t2sr:value&gt;<b>BAR</b>&lt;/t2sr:value&gt;
+&lt;/t2sr:runInput&gt;</pre></blockquote>
+  </li>
+  <li>
+  <p>Now you can start the file running. This is done by using a PUT to set
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/status</tt> to the plain text value
+  <tt>Operating</tt>.</p>
+  </li>
+  <li>
+  <p>Now you need to poll, waiting for the workflow to finish. To discover the
+  state of a run, you can (at any time) do a GET on
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/status</tt>; when the workflow has
+  finished executing, this will return <tt>Finished</tt> instead of
+  <tt>Operating</tt> (or <tt>Initialized</tt>, the starting state).</p>
+  </li>
+  <li>
+  <p>Every workflow run has an expiry time, after which it will be destroyed
+  and all resources (i.e., local files) associated with it cleaned up. By
+  default in this release, this is 20 minutes after initial creation. To see
+  when a particular run is scheduled to be disposed of, do a GET on
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/expiry</tt>; you may set the time when
+  the run is disposed of by PUTting a new time to that same URI. Note that
+  this includes not just the time when the workflow is executing, but also
+  when the input files are being created beforehand and when the results are
+  being downloaded afterwards; you are advised to make your clients regularly
+  advance the expiry time while the run is in use.</p>
+  </li>
+  <li>
+  <p>The outputs from the workflow are files created in the <tt>out</tt>
+  subdirectory of the run's working directory. The contents of the
+  subdirectory can be read by doing a GET on
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out</tt> which will return an XML
+  document describing the contents of the directory, with links to each of the
+  files within it. Doing a GET on those links will retrieve the actual created
+  files (as uninterpreted binary data).</p>
+  <p>Thus, if a single output <tt><b>FOO.OUT</b></tt> was produced from the
+  workflow, it would be written to the file that can be retrieved from
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out/<b>FOO.OUT</b></tt> and the
+  result of the GET on <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out</tt> would
+  look something like this:</p>
+  <blockquote><pre>&lt;t2sr:directoryContents xmlns:xlink="http://www.w3.org/1999/xlink"
+        xmlns:t2sr="http://ns.taverna.org.uk/2010/xml/server/rest"
+        xmlns:t2s="http://ns.taverna.org.uk/2010/xml/server/"&gt;
+    &lt;t2s:file xlink:href="%{BASEURL}/rest/runs/<b>UUID</b>/wd/out/<b>FOO.OUT</b>"
+            t2sr:name="<b>FOO.OUT</b>"&gt;out/<b>FOO.OUT</b>&lt;/t2s:file&gt;
+&lt;/t2sr:directoryContents&gt;</pre></blockquote>
+  </li>
+  <li>
+  <p>The standard output and standard error from the T2 Command Line Executor
+  subprocess can be read via properties of the special I/O listener. To do
+  that, do a GET on
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/listeners/io/properties/<b>stdout</b></tt>
+  (or <tt>.../<b>stderr</b></tt>). Once the subprocess has finished executing,
+  the I/O listener will provide a third property containing the exit code of
+  the subprocess, called <tt>exitcode</tt>.</p> <p>Note that the supported set
+  of listeners and properties will be subject to change in future versions of
+  the server, and should not be relied upon.</p>
+  </li>
+  <li>
+  <p>Once you have finished, destroy the run by doing a DELETE on
+  <tt>%{BASEURL}/rest/runs/<b>UUID</b></tt>. Once you have done that, none of
+  the resources associated with the run (including both input and output
+  files) will exist any more. If the run is still executing, this will also
+  cause it to be stopped.</p>
+  </li>
+</ol>
+<p>All operations described above have equivalents in the
+<a href="%{BASEURL}/soap?wsdl">SOAP service interface</a>.</p>
+
+<div>
+<hr>
+<p><small>Copyright &copy; 2010&ndash;2014. The University of Manchester.</small></p>
+<p><small>Software Release ID: ${project.version} (commit: ${git.branch})</small></p>
+</div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/META-INF/MANIFEST.MF b/taverna-server-webapp/src/main/webapp/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger b/taverna-server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
new file mode 100644
index 0000000..4fd9372
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
@@ -0,0 +1 @@
+org.apache.cxf.common.logging.Log4jLogger

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml b/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
new file mode 100644
index 0000000..afd640a
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/META-INF/persistence.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="1.0"
+	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd ">
+	<persistence-unit name="TavernaServer">
+		<class>org.taverna.server.master.WebappState</class>
+		<class>org.taverna.server.master.identity.User</class>
+		<class>org.taverna.server.master.localworker.PersistedState</class>
+		<class>org.taverna.server.master.notification.atom.Event</class>
+		<class>org.taverna.server.master.usage.UsageRecord</class>
+		<class>org.taverna.server.master.worker.RunConnection</class>
+		<exclude-unlisted-classes>true</exclude-unlisted-classes>
+	</persistence-unit>
+</persistence>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..73990a7
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,518 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
+	default-lazy-init="false"
+	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+	<bean id="webapp" class="org.taverna.server.master.TavernaServer">
+		<property name="policy" ref="worker.policy" />
+		<property name="runStore" ref="worker.rundb" />
+		<property name="fileUtils" ref="fileUtils" />
+		<property name="contentsDescriptorBuilder" ref="contentsDescriptorBuilder" />
+		<property name="notificationEngine" ref="notificationFabric" />
+		<property name="support" ref="webapp.support" />
+		<property name="eventSource" ref="dispatch.atom" />
+		<property name="interactionFeed" value="${taverna.interaction.feed_path}" />
+		<lookup-method name="makeRunInterface" bean="run.coreView.prototype" />
+		<lookup-method name="getPolicyDescription" bean="webapp.policyView" />
+	</bean>
+
+	<bean id="webapp.support" class="org.taverna.server.master.TavernaServerSupport">
+		<property name="policy" ref="worker.policy" />
+		<property name="listenerFactory" ref="localworker.factory" />
+		<property name="runFactory" ref="localworker.factory" />
+		<property name="fileUtils" ref="fileUtils" />
+		<property name="runStore" ref="worker.rundb" />
+		<property name="stateModel" ref="webapp.state" />
+		<property name="idMapper" ref="IdentityMapper" />
+		<property name="invocationCounter" ref="webapp.invocationCounter" />
+		<property name="webapp" ref="webapp" />
+		<property name="contentTypeMap">
+			<map key-type="java.lang.String" value-type="java.lang.String">
+				<description>Maps suffixes (post '.') to content types.</description>
+				<entry key="baclava" value="application/vnd.taverna.baclava+xml" />
+				<entry key="robundle.zip" value="application/vnd.wf4ever.robundle+zip" />
+			</map>
+		</property>
+		<property name="capabilitySource" ref="capabilities" />
+	</bean>
+
+	<bean id="capabilities" class="org.taverna.server.master.utils.CapabilityLister" />
+
+	<bean id="webapp.policyView" class="org.taverna.server.master.PolicyREST">
+		<property name="support" ref="webapp.support" />
+		<property name="policy" ref="worker.policy" />
+		<property name="listenerFactory" ref="localworker.factory" />
+		<property name="notificationEngine" ref="notificationFabric" />
+	</bean>
+
+	<bean id="contentsDescriptorBuilder" class="org.taverna.server.master.ContentsDescriptorBuilder">
+		<property name="uriBuilderFactory" ref="webapp" />
+		<property name="fileUtils" ref="fileUtils" />
+	</bean>
+
+	<bean id="webapp.state" class="org.taverna.server.master.ManagementState">
+		<description>The initial state of the webapp.</description>
+		<property name="logIncomingWorkflows" value="${default.logworkflows}" />
+		<property name="allowNewWorkflowRuns" value="${default.permitsubmit}" />
+		<property name="logOutgoingExceptions" value="${default.logexceptions}" />
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<property name="self" ref="webapp.state" />
+	</bean>
+
+	<bean id="webapp.invocationCounter" class="org.taverna.server.master.utils.InvocationCounter" />
+	<bean id="webapp.perfLogger" class="org.taverna.server.master.utils.CallTimeLogger">
+		<property name="threshold" value="${calltime.logthreshold:4000000}" />
+	</bean>
+
+	<bean id="run.coreView.prototype" scope="prototype"
+		class="org.taverna.server.master.RunREST">
+		<property name="support" ref="webapp.support" />
+		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
+		<lookup-method name="makeSecurityInterface" bean="run.securityView.prototype" />
+		<lookup-method name="makeInputInterface" bean="run.inputView.prototype" />
+		<lookup-method name="makeListenersInterface" bean="run.listenersView.prototype" />
+		<lookup-method name="makeDirectoryInterface" bean="run.directoryView.prototype" />
+		<lookup-method name="makeInteractionFeed" bean="run.interactionFeed.prototype" />
+	</bean>
+
+	<bean id="run.directoryView.prototype" scope="prototype"
+		class="org.taverna.server.master.DirectoryREST">
+		<property name="support" ref="webapp.support" />
+		<property name="fileUtils" ref="fileUtils" />
+	</bean>
+
+	<bean id="run.listenersView.prototype" scope="prototype"
+		class="org.taverna.server.master.ListenersREST">
+		<property name="support" ref="webapp.support" />
+		<lookup-method name="makeListenerInterface" bean="run.singleListenerView.prototype" />
+	</bean>
+
+	<bean id="run.singleListenerView.prototype" scope="prototype"
+		class="org.taverna.server.master.SingleListenerREST">
+		<lookup-method name="makePropertyInterface" bean="run.propertyView.prototype" />
+	</bean>
+
+	<bean id="run.propertyView.prototype" scope="prototype"
+		class="org.taverna.server.master.ListenerPropertyREST">
+		<property name="support" ref="webapp.support" />
+	</bean>
+
+	<bean id="run.inputView.prototype" scope="prototype"
+		class="org.taverna.server.master.InputREST">
+		<property name="support" ref="webapp.support" />
+		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
+		<property name="fileUtils" ref="fileUtils" />
+	</bean>
+
+	<bean id="run.securityView.prototype" scope="prototype"
+		class="org.taverna.server.master.RunSecurityREST">
+		<property name="support" ref="webapp.support" />
+	</bean>
+
+	<bean id="run.interactionFeed.prototype" scope="prototype"
+		class="org.taverna.server.master.InteractionFeed">
+		<property name="interactionFeedSupport" ref="interactionFeed" />
+	</bean>
+
+	<bean id="feed" class="org.taverna.server.master.notification.atom.AtomFeed">
+		<property name="eventSource" ref="dispatch.atom" />
+		<property name="support" ref="webapp.support" />
+		<property name="feedLanguage" value="${atom.language}" />
+		<property name="abdera" ref="abdera" />
+	</bean>
+
+	<bean id="admin" class="org.taverna.server.master.admin.AdminBean">
+		<property name="adminHtmlFile" value="/admin.html" />
+		<property name="counter" ref="webapp.invocationCounter" />
+		<property name="factory" ref="localworker.factory" />
+		<property name="localWorkerModel" ref="localworker.state" />
+		<property name="runDB" ref="worker.rundb" />
+		<property name="state" ref="webapp.state" />
+		<property name="usageRecords" ref="usageRecordSink" />
+		<property name="userStore" ref="userStore" />
+	</bean>
+
+	<bean id="IdentityMapper" class="org.taverna.server.master.identity.CompositeIDMapper">
+		<property name="identityMappers">
+			<list>
+				<bean id="AuthorityBased"
+					class="org.taverna.server.master.identity.AuthorityDerivedIDMapper">
+					<description>Derives the local user identity to use for execution
+						from the LOCALUSER_* Spring Security authority. Thus, if the user
+						has &quot;LOCALUSER_foo&quot;, they will be executing as the local
+						user id &quot;foo&quot;.</description>
+				</bean>
+				<bean id="SelfAccess"
+					class="org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfIDMapper">
+					<description>Handles the case where a workflow is accessing itself for
+						the purpose of publishing interactions.</description>
+					<property name="runStore" ref="worker.rundb" />
+				</bean>
+				<bean id="Extracting" class="org.taverna.server.master.identity.NameIDMapper">
+					<description>An alternate mechanism for mapping users. This tries
+						to use an RE to extract the user name from the principal name.
+					</description>
+					<property name="regexp" value="${localusernameregexp}">
+						<description>An optional regexp to extract the local user name
+							from the principal's string description. The first capturing
+							group will be the result of the mapping operation.
+						</description>
+					</property>
+				</bean>
+				<bean id="Constant" class="org.taverna.server.master.identity.ConstantIDMapper">
+					<description>How to map web principals to local users. This one
+						maps everyone to the same user, "taverna".
+					</description>
+					<property name="constantId" value="${default.localusername}" />
+				</bean>
+			</list>
+		</property>
+	</bean>
+
+	<bean id="passwordEncoder"
+		class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
+	<bean class="org.taverna.server.master.identity.UserStore" id="userStore">
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<property name="baselineUserProperties">
+			<util:properties location="/WEB-INF/security/users.properties" />
+		</property>
+		<property name="defaultLocalUser" value="${default.localusername}" />
+		<property name="encoder" ref="passwordEncoder" />
+	</bean>
+
+	<!-- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
+		<property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> 
+		<props> <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop> 
+		<prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> <property 
+		name="annotatedClasses"> <list> </list> </property> </bean> -->
+	<bean id="pmb" class="org.taverna.server.master.utils.JDOSupport.PersistenceManagerBuilder">
+		<property name="persistenceManagerFactory">
+			<bean id="pmf" class="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
+				destroy-method="close">
+				<property name="connectionFactory" ref="dataSource" />
+				<property name="nontransactionalRead" value="true" />
+				<property name="persistenceProperties">
+					<props>
+						<prop key="datanucleus.storeManagerType">rdbms</prop>
+						<prop key="datanucleus.autoCreateTables">true</prop>
+						<prop key="datanucleus.autoCreateTables">true</prop>
+						<prop key="datanucleus.validateTables">true</prop>
+						<prop key="datanucleus.autoCreateColumns">true</prop>
+						<prop key="datanucleus.autoCreateConstraints">true</prop>
+						<prop key="datanucleus.validateConstraints">true</prop>
+						<prop key="datanucleus.autoCreateSchema">true</prop>
+						<prop key="datanucleus.PersistenceUnitName">TavernaServer</prop>
+						<prop key="datanucleus.rdbms.datastoreAdapterClassName"
+							>org.taverna.server.master.utils.LoggingDerbyAdapter</prop>
+					</props>
+				</property>
+			</bean>
+		</property>
+	</bean>
+	<bean id="transactionAspect"
+		class="org.taverna.server.master.utils.JDOSupport.TransactionAspect" />
+
+	<bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+		<description>http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file</description>
+		<property name="targetObject" value="#{@systemProperties}" />
+		<property name="targetMethod" value="putAll" />
+		<property name="arguments">
+			<util:properties>
+				<prop key="derby.stream.error.field">org.taverna.server.master.utils.DerbyUtils.TO_LOG</prop>
+				<prop key="derby.stream.error.logSeverityLevel">30000</prop>
+			</util:properties>
+		</property>
+	</bean>
+	<!-- TODO: control the location of the database properly, or move to JNDI 
+		TODO: review whether what we are doing now is correct! -->
+	<bean id="dataSource" class="org.taverna.server.master.utils.WebappAwareDataSource">
+		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
+		<property name="url"
+			value="jdbc:derby:directory:%{WEBAPPROOT}tavernaserver;create=true" />
+		<!-- Needed for Derby... -->
+		<property name="shutdownUrl"
+			value="jdbc:derby:directory:%{WEBAPPROOT}tavernaserver;shutdown=true" />
+		<property name="username" value="taverna" />
+		<property name="password" value="" />
+		<property name="contextualizer" ref="contextualizer" />
+	</bean>
+
+	<bean id="contextualizer" class="org.taverna.server.master.utils.Contextualizer" />
+
+	<bean id="usageRecordSink" class="org.taverna.server.master.usage.UsageRecordRecorder">
+		<property name="state" ref="webapp.state" />
+		<property name="contextualizer" ref="contextualizer" />
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<property name="self" ref="usageRecordSink" />
+		<property name="disableDB" value="${usage.disableDB}" />
+		<property name="logFile" value="${usage.logFile}" />
+	</bean>
+
+	<context:property-placeholder
+		ignore-unresolvable="true" order="2" properties-ref="default-factory-properties" />
+	<util:properties id="default-factory-properties">
+		<prop key="backEndFactory">org.taverna.server.master.localworker.IdAwareForkRunFactory</prop>
+	</util:properties>
+
+	<!-- This bean configuration replaced with org.taverna.server.master.localworker.LocalWorkerFactory -->
+	<!-- <bean id="localworker.factory" scope="singleton" lazy-init="false" 
+		class="${backEndFactory}"> <description> The simple policy manager and factory 
+		for the baseline localworker case. </description> <property name="state" 
+		ref="localworker.state" /> <property name="runDB" ref="worker.rundb" 
+		/> -->
+	<!-- Handled by autowiring to make type-resilient. -->
+	<!-- <property name="idMapper" ref="IdentityMapper" /> -->
+	<!-- <property name="securityContextFactory" ref="worker.securityContext" 
+		/> <property name="usageRecordSink" ref="usageRecordSink" /> <property name="URProcessorPool" 
+		ref="URThreads" /> </bean> -->
+
+	<!-- <task:executor id="URThreads" pool-size="${pool.size}" /> -->
+
+	<bean id="worker.securityContext"
+		class="org.taverna.server.master.worker.SecurityContextFactory">
+		<property name="runDatabase" ref="worker.rundb" />
+		<property name="filenameConverter" ref="fileUtils" />
+		<property name="x500Utils" ref="x500Utils" />
+		<property name="httpRealm" value="${http.realmName}" />
+		<property name="uriSource" ref="webapp" />
+		<property name="certificateFetcher" ref="certificateChainFetcher" />
+		<property name="passwordIssuer" ref="passwordIssuer" />
+	</bean>
+
+	<bean id="passwordIssuer" class="org.taverna.server.master.worker.PasswordIssuer">
+		<!-- <property name="length" value="8" /> -->
+	</bean>
+
+	<bean id="certificateChainFetcher" class="org.taverna.server.master.utils.CertificateChainFetcher">
+		<property name="secure" value="${fetchCertificateChain}" />
+	</bean>
+
+	<bean id="localworker.state" class="org.taverna.server.master.localworker.LocalWorkerState"
+		scope="singleton" lazy-init="false">
+		<description>
+			The state of the simple factory for the identity-aware
+			local worker.
+		</description>
+		<property name="defaultLifetime" value="${default.lifetime}">
+			<description>How long the run lasts for by default, in seconds.
+			</description>
+		</property>
+		<property name="maxRuns" value="${default.runlimit}">
+			<description>The maximum simultaneous number of runs.</description>
+		</property>
+		<property name="operatingLimit" value="${default.operatinglimit}">
+			<description>
+				The maximum number of runs that are in the Operating state,
+				i.e., actually running with a process consuming resources.
+			</description>
+		</property>
+		<property name="extraArgs">
+			<description>Any extra arguments (memory control, etc.) to pass to
+				the spawned subprocesses.
+			</description>
+			<list>
+			</list>
+		</property>
+		<property name="waitSeconds" value="40">
+			<description>An upper bound (in seconds) on the time to wait for a
+				subprocess to start before failing it.
+			</description>
+		</property>
+		<property name="sleepMS" value="1000">
+			<description>The time to wait (in milliseconds) between polling for
+				the subprocess to complete its registration.
+			</description>
+		</property>
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<!-- <property name="javaBinary"> <description>The name of the java executable 
+			used to run the server worker. Defaults to the executable used to run the 
+			hosting environment.</description> </property> -->
+		<!-- <property name="serverWorkerJar"> <description>The full path to the 
+			executable JAR file containing the implementation of the server worker.</description> 
+			</property> -->
+		<!-- <property name="executeWorkflowScript"> <description>The full path 
+			to the executeworkflow.sh in either the Taverna 2 Workbench distribution 
+			or the Taverna 2 Command Line distribution.</description> </property> -->
+		<property name="self" ref="localworker.state" />
+		<property name="defaultExecuteWorkflowScript" value="${executeWorkflowScript:NONE}" />
+	</bean>
+
+	<bean id="worker.policy" class="org.taverna.server.master.worker.PolicyImpl">
+		<description>
+			The implementation of the access control policy supported
+			by the localworker run engine.
+		</description>
+		<property name="limits" ref="localworker.state" />
+		<property name="runDB" ref="worker.rundb" />
+	</bean>
+	<bean id="worker.rundb" class="org.taverna.server.master.worker.RunDatabase">
+		<property name="notifier" ref="worker.notifier" />
+		<property name="typeNotifiers">
+			<list>
+				<ref bean="cn.email" />
+				<ref bean="cn.sms" />
+				<ref bean="cn.twitter" />
+				<!-- <ref bean="cn.xmpp"/> -->
+			</list>
+		</property>
+		<property name="notificationEngine" ref="notificationFabric" />
+		<property name="dao" ref="worker.runDAO" />
+	</bean>
+	<bean id="cn.email"
+		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		<property name="name" value="email" />
+		<property name="subject" value="Workflow run finished executing" />
+		<property name="velocityEngine" ref="velocity" />
+		<property name="uriBuilderFactory" ref="webapp" />
+	</bean>
+	<bean id="cn.sms"
+		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		<property name="name" value="sms" />
+		<property name="subject" value="Run finished" />
+		<property name="velocityEngine" ref="velocity" />
+		<property name="uriBuilderFactory" ref="webapp" />
+	</bean>
+	<bean id="cn.twitter"
+		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
+		<property name="name" value="twitter" />
+		<property name="subject" value="Run finished" />
+		<property name="velocityEngine" ref="velocity" />
+		<property name="uriBuilderFactory" ref="webapp" />
+	</bean>
+	
+	<bean id="worker.runDAO" class="org.taverna.server.master.worker.RunDatabaseDAO">
+		<description>
+			The implementation of the catalog of workflow runs
+			supported by the localworker run engine.
+		</description>
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<property name="facade" ref="worker.rundb" />
+	</bean>
+	<task:scheduled-tasks scheduler="taskScheduler">
+		<task:scheduled ref="worker.rundb" method="cleanNow"
+			fixed-delay="${purge.interval}" />
+		<task:scheduled ref="worker.rundb" method="checkForFinishNow"
+			fixed-delay="${finish.interval}" />
+		<task:scheduled ref="dispatch.atom" method="deleteExpiredEvents"
+			fixed-delay="${atom.cleaninterval}" />
+	</task:scheduled-tasks>
+
+	<bean id="notificationFabric"
+		class="org.taverna.server.master.notification.NotificationEngine">
+		<property name="dispatchers">
+			<list>
+				<ref bean="dispatch.email" />
+				<ref bean="dispatch.twitter" />
+				<ref bean="dispatch.xmpp" />
+				<ref bean="dispatch.sms" />
+			</list>
+		</property>
+		<property name="universalDispatchers">
+			<list>
+				<ref bean="dispatch.atom" />
+			</list>
+		</property>
+	</bean>
+
+	<bean id="dispatch.email" class="org.taverna.server.master.notification.EmailDispatcher">
+		<property name="from" value="${email.from}" />
+		<property name="messageContentType" value="${email.type}" />
+		<property name="cooldownSeconds" value="${message.cooldown}" />
+		<property name="smtpHost" value="${email.host}" />
+		<property name="sender">
+			<bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
+				id="javamail">
+				<property name="host" value="${email.host}" />
+			</bean>
+		</property>
+	</bean>
+	<bean id="dispatch.twitter"
+		class="org.taverna.server.master.notification.TwitterDispatcher">
+		<property name="cooldownSeconds" value="${message.cooldown}" />
+		<property name="accessToken" value="${twitter.oauth.accessToken}" />
+		<property name="accessSecret" value="${twitter.oauth.accessTokenSecret}" />
+	</bean>
+	<bean id="dispatch.xmpp" class="org.taverna.server.master.notification.JabberDispatcher">
+		<property name="resource" value="${xmpp.resource}" />
+		<property name="host" value="${xmpp.service}" />
+		<property name="username" value="${xmpp.user}" />
+		<property name="password" value="${xmpp.password}" />
+	</bean>
+	<bean id="dispatch.sms" class="org.taverna.server.master.notification.SMSDispatcher">
+		<property name="usernameField" value="${sms.userfield}" />
+		<property name="passwordField" value="${sms.passfield}" />
+		<property name="destinationField" value="${sms.destfield}" />
+		<property name="messageField" value="${sms.msgfield}" />
+		<property name="cooldownSeconds" value="${message.cooldown}" />
+	</bean>
+
+	<bean id="dispatch.atom" class="org.taverna.server.master.notification.atom.EventDAO">
+		<property name="expiryAgeDays" value="${atom.lifespan}" />
+		<property name="persistenceManagerBuilder" ref="pmb" />
+		<property name="uriBuilderFactory" ref="feed" />
+		<property name="self" ref="dispatch.atom" />
+	</bean>
+
+	<bean id="worker.notifier"
+		class="org.taverna.server.master.worker.SimpleFormattedCompletionNotifier">
+		<property name="subject" value="${message.termination.subject}" />
+		<property name="messageFormat" value="${message.termination.body}" />
+		<property name="name" value="fallback"/>
+	</bean>
+
+	<bean id="fileUtils" class="org.taverna.server.master.utils.FilenameUtils" />
+	<bean id="x500Utils" class="org.taverna.server.master.utils.X500Utils" />
+	<task:scheduler id="taskScheduler" pool-size="${pool.size}" />
+
+	<bean class="org.taverna.server.master.utils.JCECheck" id="JCECheck" />
+
+	<bean class="org.taverna.server.master.interaction.InteractionFeedSupport"
+		id="interactionFeed" scope="singleton">
+		<property name="abdera" ref="abdera" />
+		<property name="support" ref="webapp.support" />
+		<property name="uriBuilder" ref="webapp" />
+		<property name="utils" ref="fileUtils" />
+	</bean>
+	<bean class="org.taverna.server.master.rest.handler.FeedHandler" id="atomFeedHandler">
+		<property name="abdera" ref="abdera" />
+	</bean>
+	<bean class="org.taverna.server.master.rest.handler.EntryHandler" id="atomEntryHandler">
+		<property name="abdera" ref="abdera" />
+	</bean>
+
+	<bean id="authProvider" class="org.taverna.server.master.identity.StrippedDownAuthProvider">
+		<property name="passwordEncoder" ref="passwordEncoder" />
+		<property name="userDetailsService">
+			<bean class="org.taverna.server.master.identity.UserStore.CachedUserStore">
+				<property name="realStore" ref="userStore" />
+			</bean>
+		</property>
+	</bean>
+	<bean id="workflowInternalAuthProvder"
+		class="org.taverna.server.master.identity.WorkflowInternalAuthProvider">
+		<property name="dao" ref="worker.runDAO" />
+		<property name="cacheBound" value="${default.runlimit}" />
+	</bean>
+	<bean id="velocity" class="org.apache.velocity.app.VelocityEngine"
+		init-method="init" lazy-init="false">
+		<constructor-arg>
+			<props>
+				<prop key="input.encoding">UTF-8</prop>
+				<prop key="output.encoding">UTF-8</prop>
+				<prop key="runtime.log.logsystem.class">org.apache.velocity.runtime.log.Log4JLogChute</prop>
+				<prop key="runtime.log.logsystem.log4j.logger">org.taverna.server.master.worker.VelocityCompletionNotifier</prop>
+				<prop key="resource.loader">class</prop>
+				<prop key="class.resource.loader.description">Velocity Classpath Resource Loader</prop>
+				<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
+			</props>
+		</constructor-arg>
+	</bean>
+	<bean id="abdera" class="org.apache.abdera.Abdera"/>
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
new file mode 100644
index 0000000..92c0b03
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/insecure.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:security="http://www.springframework.org/schema/security"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
+		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
+
+	<description>
+		The Taverna Server bean, plus supporting configuration.
+		THIS IS AN INSECURE CONFIGURATION!
+	</description>
+
+	<import resource="webappBeans.xml" />
+
+	<context:property-placeholder order="0" ignore-unresolvable="true"
+		 properties-ref="security.override.properties" />
+	<util:properties id="security.override.properties">
+		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
+		<prop key="fetchCertificateChain">false</prop>
+		<prop key="suppressRewriteEngine">true</prop>
+		<prop key="requiredChannel">any</prop>
+	</util:properties>
+
+	<!-- No JMX support; assume too unsafe. -->
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
new file mode 100644
index 0000000..d706fed
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
@@ -0,0 +1,15 @@
+Your workflow, $name, has #if( $prop_exitcode == 0)finished#{else}failed#{end}.
+
+It started execution at ${startTime}.
+It finished execution at ${finishTime}.
+
+For further information, go to $uriBuilder.build() before the run is
+automatically deleted (currently scheduled to happen at ${expiryTime}).
+
+#if( $prop_exitcode == 0)
+Exit code: $prop_exitcode
+Standard error:
+$prop_stderr
+#end
+
+(This message was automatically generated by Taverna Server ${serverVersion}.)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
new file mode 100644
index 0000000..b595931
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
@@ -0,0 +1 @@
+Taverna Server ${serverVersion}: Workflow "$name" from ${startTime} has #if( $prop_exitcode == 0)finished#{else}failed#{end}.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
new file mode 100644
index 0000000..cd920a7
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
@@ -0,0 +1 @@
+Your workflow, $name, has #if( $prop_exitcode == 0)finished#{else}failed#{end}. $uriBuilder.build() #TavernaServer ${serverVersion}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
new file mode 100644
index 0000000..2e27b81
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/partsecure.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011-2012 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xmlns:security="http://www.springframework.org/schema/security"
+	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
+
+	<description>
+		The Taverna Server bean, plus supporting configuration.
+		THIS IS THE CONFIGURATION FOR SEMI-SECURE OPERATION ON WINDOWS.
+	</description>
+
+	<import resource="webappBeans.xml" />
+
+	<!-- This is all the same as the secure config *EXCEPT* for this override. -->
+	<context:property-placeholder order="0" ignore-unresolvable="true"
+		 properties-ref="security.override.properties" />
+	<util:properties id="security.override.properties">
+		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
+		<prop key="fetchCertificateChain">true</prop>
+		<prop key="suppressRewriteEngine">false</prop>
+		<prop key="requiredChannel">https</prop>
+	</util:properties>
+
+	<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
+		<property name="locateExistingServerIfPossible" value="true" />
+	</bean>
+	<context:mbean-export server="MBeanServer"
+		default-domain="${my.domain}" registration="ignoreExisting" />
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
new file mode 100644
index 0000000..43531ab
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/providers.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
+
+	<import resource="beans.xml" />
+
+	<bean id="ExceptionProvider.BadInputPortName" class="org.taverna.server.master.rest.handler.BadInputPortNameHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.BadPropertyValue" class="org.taverna.server.master.rest.handler.BadPropertyValueHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.BadStateChange" class="org.taverna.server.master.rest.handler.BadStateChangeHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.FilesystemAccess" class="org.taverna.server.master.rest.handler.FilesystemAccessHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.GeneralFailure" class="org.taverna.server.master.rest.handler.GeneralFailureHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.IllegalArgument" class="org.taverna.server.master.rest.handler.IllegalArgumentHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.ImplementationProblem"
+		class="org.taverna.server.master.rest.handler.ImplementationProblemHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.InvalidCredential" class="org.taverna.server.master.rest.handler.InvalidCredentialHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoCreate" class="org.taverna.server.master.rest.handler.NoCreateHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.Overloaded" class="org.taverna.server.master.rest.handler.OverloadedHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoCredential" class="org.taverna.server.master.rest.handler.NoCredentialHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoDestroy" class="org.taverna.server.master.rest.handler.NoDestroyHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoDirectoryEntry" class="org.taverna.server.master.rest.handler.NoDirectoryEntryHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoListener" class="org.taverna.server.master.rest.handler.NoListenerHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NoUpdate" class="org.taverna.server.master.rest.handler.NoUpdateHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.NotOwner" class="org.taverna.server.master.rest.handler.NotOwnerHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.UnknownRun" class="org.taverna.server.master.rest.handler.UnknownRunHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.JAXBException" class="org.taverna.server.master.rest.handler.JAXBExceptionHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+	<bean id="ExceptionProvider.AccessDenied" class="org.taverna.server.master.rest.handler.AccessDeniedHandler">
+		<property name="managementModel" ref="webapp.state" />
+	</bean>
+    <bean id="ExceptionProvider.NegotiationFailed" class="org.taverna.server.master.rest.handler.NegotiationFailedHandler">
+    </bean>
+	<bean id="MessagingProvider.File" class="org.taverna.server.master.rest.handler.FileMessageHandler">
+		<property name="maxChunkSize" value="${default.messageSize}" />
+	</bean>
+	<bean id="MessagingProvider.FileConcatenation" class="org.taverna.server.master.rest.handler.FileConcatenationHandler">
+		<property name="maxChunkSize" value="${default.messageSize}" />
+	</bean>
+	<bean id="MessagingProvider.FileSegment" class="org.taverna.server.master.rest.handler.FileSegmentHandler">
+		<property name="maxChunkSize" value="${default.messageSize}" />
+	</bean>
+	<bean id="MessagingProvider.InputStream"
+		class="org.taverna.server.master.rest.handler.InputStreamMessageHandler">
+	</bean>
+	<bean id="MessagingProvider.T2flow" class="org.taverna.server.master.rest.handler.T2FlowDocumentHandler">
+	</bean>
+	<bean id="MessagingProvider.Permission" class="org.taverna.server.master.rest.handler.PermissionHandler">
+	</bean>
+
+	<bean id="Provider.RuntimeExceptionRemapping" class="org.taverna.server.master.utils.RuntimeExceptionWrapper" />
+	<bean id="MessagingProvider.ZipStream" class="org.taverna.server.master.rest.handler.ZipStreamHandler" />
+	<bean id="MessagingProvider.URIList" class="org.taverna.server.master.rest.handler.URIListHandler" />
+	<bean id="Interceptor.FlushThreadLocalCache"
+		class="org.taverna.server.master.utils.FlushThreadLocalCacheInterceptor"
+		lazy-init="false">
+	</bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/secure.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/secure.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/secure.xml
new file mode 100644
index 0000000..cf08083
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/secure.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:security="http://www.springframework.org/schema/security"
+	xsi:schemaLocation="
+	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+	http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
+
+	<description>
+		The Taverna Server bean, plus supporting configuration.
+		THIS IS THE CONFIGURATION FOR SECURE OPERATION.
+	</description>
+
+	<import resource="webappBeans.xml" />
+
+	<context:property-placeholder order="0" ignore-unresolvable="true"
+		 properties-ref="security.override.properties" />
+	<util:properties id="security.override.properties">
+		<prop key="fetchCertificateChain">true</prop>
+		<prop key="suppressRewriteEngine">false</prop>
+		<prop key="requiredChannel">https</prop>
+	</util:properties>
+
+	<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
+		<property name="locateExistingServerIfPossible" value="true" />
+	</bean>
+	<context:mbean-export server="MBeanServer"
+		default-domain="${my.domain}" registration="ignoreExisting" />
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/security/users.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/security/users.properties b/taverna-server-webapp/src/main/webapp/WEB-INF/security/users.properties
new file mode 100644
index 0000000..03f8436
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/security/users.properties
@@ -0,0 +1,48 @@
+# This is a Java properties file that defines the default users supported by
+# Taverna Server. The keys are the user names, and the values are comma-
+# -separated lists of values: the first is the password (which must not have
+# any spaces or commas in) and the last is "enabled" or "disabled" to indicate
+# whether this user is actually allowed to log in or not. The values between
+# are the authorities associated with the user: these are either roles (which
+# describe a particular set of permissions for the user) or user mappings.
+#
+# The supported set of authorities are:
+#
+#   ROLE_tavernauser      - may use the standard Taverna Server interfaces
+#
+#   ROLE_tavernasuperuser - may use the admin interfaces and see *all*
+#                           workflow runs irrespective of permissions
+#
+#   LOCALUSER_*           - map the server user to the given local system
+#                           account (i.e., the account name is in place of the
+#                           "*" in the authority); don't grant two of these
+#                           authorities at once, or confusion will reign
+#
+# Note that it is usually better to define accounts via the administrative
+# interface or through the JMX interface because those can then be modified
+# without restarting the server; anything in this file is fixed until the
+# next server restart. This file exists mainly to allow permissions for the
+# admin interface to be boot-strapped.
+
+# ---------------------------------------------------------------------
+
+# A normal user. Must have given role (ROLE_tavernauser) to use Taverna Server.
+# The user has password "taverna" and is enabled. The default mapping to user
+# accounts - using the user name - will be used.
+
+taverna: taverna,ROLE_tavernauser,enabled
+
+# Another normal user (username: "taverna_alt"). Will be mapped to the system
+# account called "taverna", but the user is currently disabled.
+
+taverna_alt: qwerty,ROLE_tavernauser,LOCALUSER_taverna,disabled
+
+# The default admin user, who has password "admin". You should change this!
+# Admin users also have ROLE_tavernasuperuser, which grants access to the
+# server's /admin pages and allows all workflow runs to be seen (if the
+# ROLE_tavernauser is also assigned, as below; one does not imply the other).
+# If you don't have any enabled admin users, you'll need to use JMX to do
+# management operations (JMX is only accessible from the local host and by
+# the overall container user or the system administrator).
+
+admin: admin,ROLE_tavernauser,ROLE_tavernasuperuser,LOCALUSER_taverna,enabled

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties b/taverna-server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
new file mode 100644
index 0000000..9616a45
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
@@ -0,0 +1,77 @@
+# Override the hostname, port and webapp; leave at 'NONE' if no override
+# desired. If set, set it to something like:
+#      foo.example.com:8000/tav-serv
+default.webapp:			NONE
+# User name to use if nothing else specified
+default.localusername:	taverna
+# How to pick a user name out of a global identity
+localusernameregexp:	^TAVERNAUSER=(.*)$
+# General defaults
+default.logworkflows:	false
+default.logexceptions:	false
+default.permitsubmit:	true
+default.lifetime:		1440
+default.runlimit:		100
+default.operatinglimit:	10
+default.messageSize:	65536
+#taverna.preferredUserUri:	https://some.host:8443/tavernaserver/rest/
+http.realmName:         tavernaserver
+
+rmi.localhostOnly:		true
+helio.cis.enableTokenPassing:	false
+log.security.details:	false
+
+#executeWorkflowScript:	/usr/taverna/executeworkflow.sh
+#secureForkPasswordFile:	/usr/local/tomcat6.0/conf/sudopass.txt
+
+# Usage Record handling
+usage.logFile:		none
+usage.disableDB:	no
+
+# Delays used in the task executor 
+purge.interval:		30000
+finish.interval:	10000
+
+# Static configuration of messaging
+
+### Email
+email.from:		taverna.server@localhost
+email.type:		text/plain
+#email.host:	localhost
+
+### Jabber
+#xmpp.server:	xmpp://some.host:5222
+xmpp.resource:	TavernaServer
+#xmpp.user:		taverna
+#xmpp.password:	*******
+
+### Atom/RSS; lifespan in days, cleaninterval in milliseconds
+atom.language:	en
+atom.lifespan:	7
+atom.cleaninterval:	3600000
+
+### SMS
+#sms.service:	https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx
+sms.userfield:	username
+sms.passfield:	password
+sms.destfield:	to
+sms.msgfield:	text
+#sms.user:		taverna
+#sms.pass:		*******
+
+### Twitter
+#twitter.oauth.accessToken:			...
+#twitter.oauth.accessTokenSecret:	...
+
+### General; cooldown in seconds
+message.cooldown:				300
+message.termination.subject:	Taverna workflow run finished
+message.termination.body:		Your job with ID={0} has finished with exit code {1,number,integer}.
+
+# Thread pool sizing
+pool.size:	2
+
+taverna.interaction.host:			none
+taverna.interaction.port:			none
+taverna.interaction.webdav_path:	none
+taverna.interaction.feed_path:		none

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/web-nosec.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
new file mode 100644
index 0000000..d6c6ee7
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<web-app id="TAVSERV-2.5.4">
+	<display-name>Taverna 2.5.4 Server</display-name>
+	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>WEB-INF/insecure.xml</param-value>
+		<description>Where Spring is to load its bean definitions from. DO NOT
+			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
+	</context-param>
+	<context-param>
+		<param-name>log4jExposeWebAppRoot</param-name>
+		<param-value>false</param-value>
+		<description>
+			THIS IS STUPID! We have to do this so that Tomcat webapps do not
+			leak their configurations into each other via the log4j support
+			trying to be "smart".
+			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
+			If you change this, good luck hunting down the weird crashes.
+		</description>
+	</context-param>
+
+	<filter>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+	</filter>
+	<filter-mapping>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.request.RequestContextListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.util.Log4jConfigListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.ContextLoaderListener
+		</listener-class>
+	</listener>
+
+	<servlet>
+		<servlet-name>CXFServlet</servlet-name>
+		<display-name>CXF Servlet</display-name>
+		<servlet-class>
+			org.apache.cxf.transport.servlet.CXFServlet
+		</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>CXFServlet</servlet-name>
+		<url-pattern>/*</url-pattern>
+	</servlet-mapping>
+
+	<resource-ref>
+		<description>
+			Resource reference to a factory for javax.mail.Session
+			instances that may be used for sending electronic mail
+			messages, preconfigured to connect to the appropriate
+			SMTP server.
+		</description>
+		<res-ref-name>mail/Session</res-ref-name>
+		<res-type>javax.mail.Session</res-type>
+		<res-auth>Container</res-auth>
+		<res-sharing-scope>Shareable</res-sharing-scope>
+	</resource-ref>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/web-partsec.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
new file mode 100644
index 0000000..a2b545e
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<web-app id="TAVSERV-2.5.4">
+	<display-name>Taverna 2.5.4 Server</display-name>
+	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>WEB-INF/partsecure.xml</param-value>
+		<description>Where Spring is to load its bean definitions from. DO NOT
+			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
+	</context-param>
+	<context-param>
+		<param-name>log4jExposeWebAppRoot</param-name>
+		<param-value>false</param-value>
+		<description>
+			THIS IS STUPID! We have to do this so that Tomcat webapps do not
+			leak their configurations into each other via the log4j support
+			trying to be "smart".
+			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
+			If you change this, good luck hunting down the weird crashes.
+		</description>
+	</context-param>
+
+	<filter>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+	</filter>
+	<filter-mapping>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.request.RequestContextListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.util.Log4jConfigListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.ContextLoaderListener
+		</listener-class>
+	</listener>
+
+	<servlet>
+		<servlet-name>CXFServlet</servlet-name>
+		<display-name>CXF Servlet</display-name>
+		<servlet-class>
+			org.apache.cxf.transport.servlet.CXFServlet
+		</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>CXFServlet</servlet-name>
+		<url-pattern>/*</url-pattern>
+	</servlet-mapping>
+
+	<resource-ref>
+		<description>
+			Resource reference to a factory for javax.mail.Session
+			instances that may be used for sending electronic mail
+			messages, preconfigured to connect to the appropriate
+			SMTP server.
+		</description>
+		<res-ref-name>mail/Session</res-ref-name>
+		<res-type>javax.mail.Session</res-type>
+		<res-auth>Container</res-auth>
+		<res-sharing-scope>Shareable</res-sharing-scope>
+	</resource-ref>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/web-sec.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/web-sec.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/web-sec.xml
new file mode 100644
index 0000000..9a5395a
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/web-sec.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<web-app id="TAVSERV-2.5.4">
+	<display-name>Taverna 2.5.4 Server</display-name>
+	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>WEB-INF/secure.xml</param-value>
+		<description>Where Spring is to load its bean definitions from. DO NOT
+			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
+	</context-param>
+	<context-param>
+		<param-name>log4jExposeWebAppRoot</param-name>
+		<param-value>false</param-value>
+		<description>
+			THIS IS STUPID! We have to do this so that Tomcat webapps do not
+			leak their configurations into each other via the log4j support
+			trying to be "smart".
+			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
+			If you change this, good luck hunting down the weird crashes.
+		</description>
+	</context-param>
+
+	<filter>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+	</filter>
+	<filter-mapping>
+		<filter-name>springSecurityFilterChain</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.request.RequestContextListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.util.Log4jConfigListener
+		</listener-class>
+	</listener>
+	<listener>
+		<listener-class>
+			org.springframework.web.context.ContextLoaderListener
+		</listener-class>
+	</listener>
+
+	<servlet>
+		<servlet-name>CXFServlet</servlet-name>
+		<display-name>CXF Servlet</display-name>
+		<servlet-class>
+			org.apache.cxf.transport.servlet.CXFServlet
+		</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>CXFServlet</servlet-name>
+		<url-pattern>/*</url-pattern>
+	</servlet-mapping>
+
+	<resource-ref>
+		<description>
+			Resource reference to a factory for javax.mail.Session
+			instances that may be used for sending electronic mail
+			messages, preconfigured to connect to the appropriate
+			SMTP server.
+		</description>
+		<res-ref-name>mail/Session</res-ref-name>
+		<res-type>javax.mail.Session</res-type>
+		<res-auth>Container</res-auth>
+		<res-sharing-scope>Shareable</res-sharing-scope>
+	</resource-ref>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml b/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
new file mode 100644
index 0000000..22e74b3
--- /dev/null
+++ b/taverna-server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
+	for license terms. -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:jaxrs="http://cxf.apache.org/jaxrs"
+	xmlns:jaxws="http://cxf.apache.org/jaxws"
+	xmlns:cxf="http://cxf.apache.org/core"
+	xmlns:security="http://www.springframework.org/schema/security"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+		http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
+		http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
+		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+		http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
+		http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
+
+	<description>
+		The Taverna Server bean, plus supporting configuration.
+	</description>
+
+	<import resource="classpath:META-INF/cxf/cxf.xml" />
+	<import resource="providers.xml" />
+
+	<context:annotation-config />
+	<context:component-scan base-package="org.taverna.server" />
+	<bean id="servletContextPropertyConfigurer"
+		class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
+		<property name="ignoreUnresolvablePlaceholders" value="true" />
+		<property name="localOverride" value="true" />
+		<property name="order" value="0" />
+		<property name="location" value="/WEB-INF/tavernaserver.properties" />
+	</bean>
+
+	<jaxws:server id="master_SOAP"
+		serviceClass="org.taverna.server.master.TavernaServer" address="/soap">
+		<jaxws:serviceBean>
+			<ref bean="webapp" />
+		</jaxws:serviceBean>
+		<jaxws:properties>
+			<entry key="mtom-enabled" value="true" />
+		</jaxws:properties>
+		<!-- <jaxws:dataBinding><ref bean="addStylesheet"/></jaxws:dataBinding> -->
+	</jaxws:server>
+
+	<jaxrs:server id="root_REST" address="/">
+		<jaxrs:serviceBeans>
+			<ref bean="root_facade" />
+		</jaxrs:serviceBeans>
+		<jaxrs:properties>
+			<entry key="org.apache.cxf.endpoint.private" value="true" />
+		</jaxrs:properties>
+	</jaxrs:server>
+
+	<jaxrs:server id="master_REST" address="/rest"
+		staticSubresourceResolution="true">
+		<jaxrs:serviceBeans>
+			<ref bean="webapp" />
+		</jaxrs:serviceBeans>
+		<jaxrs:features>
+			<!-- <cxf:logging /> --><!-- NOISY! -->
+		</jaxrs:features>
+		<jaxrs:providers>
+			<ref bean="ExceptionProvider.AccessDenied" />
+			<ref bean="ExceptionProvider.BadInputPortName" />
+			<ref bean="ExceptionProvider.BadPropertyValue" />
+			<ref bean="ExceptionProvider.BadStateChange" />
+			<ref bean="ExceptionProvider.FilesystemAccess" />
+			<ref bean="ExceptionProvider.GeneralFailure" />
+			<ref bean="ExceptionProvider.IllegalArgument" />
+			<ref bean="ExceptionProvider.ImplementationProblem" />
+			<ref bean="ExceptionProvider.InvalidCredential" />
+			<ref bean="ExceptionProvider.JAXBException" />
+			<ref bean="ExceptionProvider.NegotiationFailed" />
+			<ref bean="ExceptionProvider.NoCreate" />
+			<ref bean="ExceptionProvider.NoCredential" />
+			<ref bean="ExceptionProvider.NoDestroy" />
+			<ref bean="ExceptionProvider.NoDirectoryEntry" />
+			<ref bean="ExceptionProvider.NoListener" />
+			<ref bean="ExceptionProvider.NoUpdate" />
+			<ref bean="ExceptionProvider.NotOwner" />
+			<ref bean="ExceptionProvider.Overloaded" />
+			<ref bean="ExceptionProvider.UnknownRun" />
+			<ref bean="MessagingProvider.File" />
+			<ref bean="MessagingProvider.FileConcatenation" />
+			<ref bean="MessagingProvider.FileSegment" />
+			<ref bean="MessagingProvider.InputStream" />
+			<ref bean="MessagingProvider.T2flow" />
+			<ref bean="MessagingProvider.Permission" />
+			<ref bean="MessagingProvider.URIList" />
+			<ref bean="MessagingProvider.ZipStream" />
+			<ref bean="jsonProvider" />
+			<ref bean="atomEntryHandler" />
+			<ref bean="atomFeedHandler" />
+			<bean class="org.apache.cxf.jaxrs.model.wadl.WadlGenerator">
+				<property name="addResourceAndMethodIds" value="true"/>
+			</bean>
+		</jaxrs:providers>
+		<jaxrs:outInterceptors>
+			<ref bean="Interceptor.FlushThreadLocalCache" />
+		</jaxrs:outInterceptors>
+ 	</jaxrs:server>
+
+	<jaxrs:server id="AtomFeed" address="/feed">
+		<jaxrs:serviceBeans>
+			<ref bean="feed" />
+		</jaxrs:serviceBeans>
+		<jaxrs:properties>
+			<entry key="org.apache.cxf.endpoint.private" value="true" />
+		</jaxrs:properties>
+		<jaxrs:providers>
+			<ref bean="atomEntryHandler" />
+			<ref bean="atomFeedHandler" />
+		</jaxrs:providers>
+	</jaxrs:server>
+
+	<jaxrs:server id="AdministrationInterface" address="/admin"
+		staticSubresourceResolution="true">
+		<jaxrs:serviceBeans>
+			<ref bean="admin" />
+		</jaxrs:serviceBeans>
+		<jaxrs:providers>
+			<ref bean="jsonProvider" />
+		</jaxrs:providers>
+	</jaxrs:server>
+
+	<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
+		<property name="ignoreNamespaces" value="true" />
+		<property name="namespaceMap" ref="jsonNamespaceMap" />
+	</bean>
+	<util:map id="jsonNamespaceMap" key-type="java.lang.String"
+		value-type="java.lang.String">
+		<entry key="http://www.w3.org/1999/xlink" value="" />
+		<entry key="http://www.w3.org/2000/09/xmldsig#" value="" />
+		<entry key="http://schema.ogf.org/urf/2003/09/urf" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/xml/server/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/xml/server/rest/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/xml/server/soap/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/xml/server/feed/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/xml/server/admin/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/port/" value="" />
+		<entry key="http://ns.taverna.org.uk/2010/run/" value="" />
+	</util:map>
+
+	<bean id="root_facade" class="org.taverna.server.master.facade.Facade">
+		<property name="file" value="/welcome.html" />
+		<property name="contextualizer" ref="contextualizer" />
+	</bean>
+
+	<bean class="org.taverna.server.master.common.Uri.Rewriter"
+		autowire="byType" id="URI-Rewriter-Thunk">
+		<property name="suppressSecurity" value="${suppressRewriteEngine}" />
+		<property name="rewriteTarget" value="${default.webapp}" />
+	</bean>
+	<security:authentication-manager>
+		<security:authentication-provider ref="workflowInternalAuthProvder" />
+		<security:authentication-provider ref="authProvider" />
+	</security:authentication-manager>
+
+	<bean id="WSDLHeadOptionsInterceptor"
+		class="org.taverna.server.master.utils.WSDLHeadOptionsInterceptor" />
+	<cxf:bus>
+		<cxf:inInterceptors>
+			<ref bean="WSDLHeadOptionsInterceptor" />
+		</cxf:inInterceptors>
+	</cxf:bus>
+
+	<aop:aspectj-autoproxy proxy-target-class="true" />
+	<security:global-method-security
+		jsr250-annotations="enabled" />
+
+	<security:http realm="${http.realmName}" create-session="never"
+		use-expressions="true">
+		<security:http-basic />
+		<security:intercept-url pattern="/"
+			requires-channel="any" access="permitAll" />
+		<security:intercept-url pattern="/rest"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/rest/"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/rest/policy"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/rest/policy/"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/services/**"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/soap/**" method="GET"
+			requires-channel="${requiredChannel}" access="permitAll" />
+		<security:intercept-url pattern="/soap/**" method="POST"
+			requires-channel="${requiredChannel}"
+			access="hasRole('ROLE_tavernauser')" />
+		<security:intercept-url pattern="/admin"
+			requires-channel="${requiredChannel}"
+			access="hasRole('ROLE_tavernasuperuser')" />
+		<security:intercept-url pattern="/admin/**"
+			requires-channel="${requiredChannel}"
+			access="hasRole('ROLE_tavernasuperuser')" />
+		<security:intercept-url pattern="/rest/**"
+			requires-channel="${requiredChannel}"
+			access="hasAnyRole('ROLE_tavernauser','ROLE_tavernaworkflow')" />
+		<security:intercept-url pattern="/feed"
+			requires-channel="${requiredChannel}"
+			access="hasRole('ROLE_tavernauser')" />
+		<security:intercept-url pattern="/feed/**"
+			requires-channel="${requiredChannel}"
+			access="hasRole('ROLE_tavernauser')" />
+	</security:http>
+</beans>


[24/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-client/pom.xml b/taverna-server-client/pom.xml
new file mode 100644
index 0000000..d16b07a
--- /dev/null
+++ b/taverna-server-client/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-client</artifactId>
+	<packaging>bundle</packaging>
+	<name>Apache Taverna Server Client OSGi Module</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.jvnet.ws.wadl</groupId>
+			<artifactId>wadl-core</artifactId>
+			<version>1.1.6</version>
+		</dependency>
+		<dependency>
+			<groupId>com.sun.jersey</groupId>
+			<artifactId>jersey-client</artifactId>
+			<version>1.8</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.4</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.tika</groupId>
+			<artifactId>tika-core</artifactId>
+			<version>1.5</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-usagerecord</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Export-Package>uk.org.taverna.server.client</Export-Package>
+						<Private-Package>uk.org.taverna.server.client.*</Private-Package>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.jvnet.ws.wadl</groupId>
+				<artifactId>wadl-client-plugin</artifactId>
+				<version>1.1.6</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>generate</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<packageName>org.taverna.server.client.wadl</packageName>
+					<includes>*.wadl</includes>
+					<customClassNames>
+						<property>
+							<name>http://example.com/taverna/rest</name>
+							<value>TavernaServer</value>
+						</property>
+					</customClassNames>
+				</configuration>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<!--This plugin's configuration is used to store Eclipse m2e settings
+					only. It has no influence on the Maven build itself. -->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>
+											org.jvnet.ws.wadl
+										</groupId>
+										<artifactId>
+											wadl-client-plugin
+										</artifactId>
+										<versionRange>
+											[1.1.6,)
+										</versionRange>
+										<goals>
+											<goal>generate</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
new file mode 100644
index 0000000..263034c
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Connected.java
@@ -0,0 +1,20 @@
+package uk.org.taverna.server.client;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+abstract class Connected {
+	void checkError(ClientResponse response) throws ClientException,
+			ServerException {
+		ClientResponse.Status s = response.getClientResponseStatus();
+		if (s.getStatusCode() == 401)
+			throw new TavernaServer.AuthorizationException("not authorized",
+					null);
+		if (s.getStatusCode() >= 500)
+			throw new TavernaServer.ServerException(s.getReasonPhrase(), null);
+		if (s.getStatusCode() >= 400)
+			throw new TavernaServer.ClientException(s.getReasonPhrase(), null);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
new file mode 100644
index 0000000..267707d
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
@@ -0,0 +1,39 @@
+package uk.org.taverna.server.client;
+
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd.Path2;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public abstract class DirEntry extends Connected {
+	final Path2 handle;
+	final String path;
+	final Run run;
+
+	protected DirEntry(Run run, String path) {
+		this.run = run;
+		this.path = path.replaceFirst("/+$", "");
+		this.handle = run.run.wd().path2(this.path);
+	}
+
+	public void delete() throws ClientException, ServerException {
+		checkError(handle.deleteAsXml(ClientResponse.class));
+	}
+
+	String path(ClientResponse response) throws ClientException, ServerException {
+		checkError(response);
+		String[] bits = response.getLocation().getPath().split("/");
+		return concat(bits[bits.length - 1]);
+	}
+
+	String localName() {
+		String[] bits = path.split("/");
+		return bits[bits.length - 1];
+	}
+
+	String concat(String name) {
+		return path + "/" + name.split("/", 2)[0];
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
new file mode 100644
index 0000000..38dc394
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Directory.java
@@ -0,0 +1,94 @@
+package uk.org.taverna.server.client;
+
+import static java.io.File.createTempFile;
+import static javax.ws.rs.client.Entity.entity;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipFile;
+
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+import uk.org.taverna.server.client.generic.DirectoryEntry;
+import uk.org.taverna.server.client.generic.DirectoryReference;
+import uk.org.taverna.server.client.generic.FileReference;
+import uk.org.taverna.server.client.rest.DirectoryContents;
+import uk.org.taverna.server.client.rest.MakeDirectory;
+import uk.org.taverna.server.client.rest.UploadFile;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public class Directory extends DirEntry {
+	private final Wd wd;
+
+	Directory(Run run) {
+		super(run, "");
+		this.wd = run.run.wd();
+	}
+
+	Directory(Run run, String path) {
+		super(run, path);
+		this.wd = run.run.wd();
+	}
+
+	public List<DirEntry> list() {
+		List<DirEntry> result = new ArrayList<>();
+		for (DirectoryEntry de : wd.path3(path)
+				.getAsXml(DirectoryContents.class).getDirOrFile())
+			if (de instanceof DirectoryReference)
+				result.add(new Directory(run, de.getValue()));
+			else if (de instanceof FileReference)
+				result.add(new File(run, de.getValue()));
+		return result;
+	}
+
+	public File createFile(String name, byte[] content) throws ClientException,
+			ServerException {
+		UploadFile uf = new UploadFile();
+		uf.setName(name);
+		uf.setValue(content);
+		return new File(run, path(wd.path(path).putAsXml(uf,
+				ClientResponse.class)));
+	}
+
+	public File createFile(String name, java.io.File content)
+			throws ClientException, ServerException {
+		return new File(run, path(wd.path(concat(name)).putOctetStreamAsXml(
+				entity(content, APPLICATION_OCTET_STREAM_TYPE),
+				ClientResponse.class)));
+	}
+
+	public File createFile(String name, URI source) throws ClientException,
+			ServerException {
+		return new File(run, path(wd.path(concat(name)).postTextUriListAsXml(
+				source.toString(), ClientResponse.class)));
+	}
+
+	public Directory createDirectory(String name) throws ClientException,
+			ServerException {
+		MakeDirectory mkdir = new MakeDirectory();
+		mkdir.setName(name);
+		return new Directory(run, path(wd.path(path).putAsXml(mkdir,
+				ClientResponse.class)));
+	}
+
+	public byte[] getZippedContents() {
+		return wd.path3(path).getAsZip(byte[].class);
+	}
+
+	public ZipFile getZip() throws IOException {
+		byte[] contents = getZippedContents();
+		java.io.File tmp = createTempFile(localName(), ".zip");
+		try (OutputStream os = new FileOutputStream(tmp)) {
+			os.write(contents);
+		}
+		return new ZipFile(tmp);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
new file mode 100644
index 0000000..0287afb
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/File.java
@@ -0,0 +1,95 @@
+package uk.org.taverna.server.client;
+
+import static java.io.File.createTempFile;
+import static javax.ws.rs.client.Entity.entity;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.apache.tika.mime.MimeTypes.getDefaultMimeTypes;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+
+import org.apache.tika.mime.MimeTypeException;
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+public class File extends DirEntry {
+	private final Wd wd;
+
+	File(Run run, String path) {
+		super(run, path);
+		wd = run.run.wd();
+	}
+
+	public InputStream getAsStream() {
+		return wd.path3(path).getAsOctetStream(InputStream.class);
+	}
+
+	public byte[] get() {
+		return wd.path3(path).getAsOctetStream(byte[].class);
+	}
+
+	public String get(Charset encoding) {
+		return new String(wd.path3(path).getAsOctetStream(byte[].class),
+				encoding);
+	}
+
+	public java.io.File getAsFile() throws ClientHandlerException,
+			UniformInterfaceException, IOException, MimeTypeException,
+			ClientException, ServerException {
+		ClientResponse cr = wd.path3(path).getAsOctetStream(
+				ClientResponse.class);
+		checkError(cr);
+		String[] bits = localName().split("[.]");
+		String ext = getDefaultMimeTypes().forName(
+				cr.getHeaders().getFirst("Content-Type")).getExtension();
+		if (ext == null)
+			ext = bits[bits.length - 1];
+		java.io.File tmp = createTempFile(bits[0], ext);
+		try (OutputStream os = new FileOutputStream(tmp);
+				InputStream is = cr.getEntity(InputStream.class)) {
+			copy(is, os);
+		}
+		return tmp;
+	}
+
+	public void setContents(byte[] newContents) throws ClientException,
+			ServerException {
+		checkError(wd.path(path).putOctetStreamAsXml(newContents,
+				ClientResponse.class));
+	}
+
+	public void setContents(String newContents) throws ClientException,
+			ServerException {
+		checkError(wd.path(path).putOctetStreamAsXml(newContents,
+				ClientResponse.class));
+	}
+
+	public void setContents(String newContents, Charset encoding)
+			throws ClientException, ServerException {
+		checkError(wd.path(path).putOctetStreamAsXml(
+				newContents.getBytes(encoding), ClientResponse.class));
+	}
+
+	public void setContents(InputStream newContents) throws ClientException,
+			ServerException {
+		checkError(wd.path(path).putOctetStreamAsXml(newContents,
+				ClientResponse.class));
+	}
+
+	public void setContents(java.io.File newContents) throws IOException,
+			ClientException, ServerException {
+		checkError(wd.path(path).putOctetStreamAsXml(
+				entity(newContents, APPLICATION_OCTET_STREAM_TYPE),
+				ClientResponse.class));
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
new file mode 100644
index 0000000..0e6542f
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Property.java
@@ -0,0 +1,18 @@
+package uk.org.taverna.server.client;
+
+public enum Property {
+	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
+			"readyToNotify"), EMAIL("notificationAddress"), USAGE(
+			"usageRecord");
+
+	private String s;
+
+	private Property(String s) {
+		this.s = s;
+	}
+
+	@Override
+	public String toString() {
+		return s;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
new file mode 100644
index 0000000..5c6875e
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Run.java
@@ -0,0 +1,215 @@
+package uk.org.taverna.server.client;
+
+import static org.joda.time.format.ISODateTimeFormat.dateTime;
+import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.io.IOUtils;
+import org.joda.time.DateTime;
+import org.ogf.usage.JobUsageRecord;
+import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName;
+import org.w3c.dom.Element;
+
+import uk.org.taverna.server.client.TavernaServer.ClientException;
+import uk.org.taverna.server.client.TavernaServer.ServerException;
+import uk.org.taverna.server.client.generic.KeyPairCredential;
+import uk.org.taverna.server.client.generic.PasswordCredential;
+import uk.org.taverna.server.client.generic.port.InputPort;
+import uk.org.taverna.server.client.generic.port.OutputPort;
+import uk.org.taverna.server.client.rest.InputDescription;
+import uk.org.taverna.server.client.rest.InputDescription.Value;
+
+import com.sun.jersey.api.client.ClientResponse;
+
+public class Run extends Connected {
+	RunsRunName run;
+
+	Run(TavernaServer server, String value) {
+		run = server.root.runsRunName(value);
+	}
+
+	public String getName() {
+		return run.name().getAsTextPlain(ClientResponse.class)
+				.getEntity(String.class);
+	}
+
+	public void setName(String name) {
+		run.name().putTextPlain(name, String.class);
+	}
+
+	public Date getExpiry() {
+		return dateTimeParser().parseDateTime(
+				run.expiry().getAsTextPlain(String.class)).toDate();
+	}
+
+	public void setExpiry(Date expiryTimestamp) {
+		run.expiry().putTextPlain(
+				dateTime().print(new DateTime(expiryTimestamp)), String.class);
+	}
+
+	public Date getCreate() {
+		String timestamp = run.createTime().getAsTextPlain(String.class);
+		if (timestamp == null || timestamp.trim().isEmpty())
+			return null;
+		return dateTimeParser().parseDateTime(timestamp).toDate();
+	}
+
+	public Date getStart() {
+		String timestamp = run.startTime().getAsTextPlain(String.class);
+		if (timestamp == null || timestamp.trim().isEmpty())
+			return null;
+		return dateTimeParser().parseDateTime(timestamp).toDate();
+	}
+
+	public Date getFinish() {
+		String timestamp = run.finishTime().getAsTextPlain(String.class);
+		if (timestamp == null || timestamp.trim().isEmpty())
+			return null;
+		return dateTimeParser().parseDateTime(timestamp).toDate();
+	}
+
+	public Status getStatus() {
+		return Status.valueOf(run.status().getAsTextPlain(String.class));
+	}
+
+	public void setStatus(Status status) {
+		run.status().putTextPlain(status, String.class);
+	}
+
+	public void start() {
+		setStatus(Status.Operating);
+	}
+
+	public void kill() {
+		setStatus(Status.Finished);
+	}
+
+	public boolean isRunning() {
+		return getStatus() == Status.Operating;
+	}
+
+	public String getStandardOutput() {
+		return run.stdout().getAsTextPlain(String.class);
+	}
+
+	public String getStandardError() {
+		return run.stderr().getAsTextPlain(String.class);
+	}
+
+	public String getLog() {
+		return run.log().getAsTextPlain(String.class);
+	}
+
+	public Integer getExitCode() {
+		String code = run.listeners().name("io")
+				.propertiesPropertyName("exitCode")
+				.getAsTextPlain(String.class);
+		if (code == null || code.trim().isEmpty())
+			return null;
+		return Integer.parseInt(code);
+	}
+
+	public String getProperty(Property prop) {
+		return run.listeners().name("io")
+				.propertiesPropertyName(prop.toString())
+				.getAsTextPlain(String.class);
+	}
+
+	public void setGenerateRunBundle(boolean generateRunBundle) {
+		run.generateProvenance().putTextPlain(generateRunBundle, String.class);
+	}
+
+	public byte[] getRunBundle() {
+		return run.runBundle().getAsVndWf4everRobundleZip(byte[].class);
+	}
+
+	public List<InputPort> getInputs() {
+		return run.input().expected().getAsInputDescriptionXml().getInput();
+	}
+
+	public List<OutputPort> getOutputs() {
+		return run.output().getAsOutputDescriptionXml().getOutput();
+	}
+
+	public void setInput(String name, String value) {
+		Value v = new Value();
+		v.setValue(value);
+		InputDescription idesc = new InputDescription();
+		idesc.setValue(v);
+		run.input().inputName(name).putXmlAsInputDescription(idesc);
+	}
+
+	public void setInput(String name, String value, char listSeparator) {
+		Value v = new Value();
+		v.setValue(value);
+		InputDescription idesc = new InputDescription();
+		idesc.setValue(v);
+		idesc.setListDelimiter(new String(new char[] { listSeparator }));
+		run.input().inputName(name).putXmlAsInputDescription(idesc);
+	}
+
+	public byte[] getWorkflow() {
+		return run.workflow().getAsVndTavernaT2flowXml(byte[].class);
+	}
+
+	// TODO Consider better ways to do this
+	public Element getInteractionFeed() {
+		return run.interaction().getAsAtomXml(Element.class);
+	}
+
+	public Element getInteractionEntry(String id) {
+		return run.interaction().id(id).getAsAtomXml(Element.class);
+	}
+
+	public JobUsageRecord getUsageRecord() throws JAXBException {
+		return JobUsageRecord.unmarshal(run.usage().getAsXml(Element.class));
+	}
+
+	public Directory getWorkingDirectory() {
+		return new Directory(this);
+	}
+
+	public String getOwner() {
+		return run.security().owner().getAsTextPlain(String.class);
+	}
+
+	// TODO permissions
+
+	public void grantPasswordCredential(URI contextService, String username,
+			String password) throws ClientException, ServerException {
+		PasswordCredential pc = new PasswordCredential();
+		pc.setServiceURI(contextService.toString());
+		pc.setUsername(username);
+		pc.setPassword(password);
+		checkError(run.security().credentials()
+				.postXmlAsOctetStream(pc, ClientResponse.class));
+	}
+
+	public void grantKeyCredential(URI contextService, java.io.File source,
+			String unlockPassword, String aliasEntry) throws IOException,
+			ClientException, ServerException {
+		KeyPairCredential kpc = new KeyPairCredential();
+		kpc.setServiceURI(contextService.toString());
+		try (InputStream in = new FileInputStream(source)) {
+			byte[] buffer = new byte[(int) source.length()];
+			IOUtils.read(in, buffer);
+			kpc.setCredentialBytes(buffer);
+		}
+		if (source.getName().endsWith(".p12"))
+			kpc.setFileType("PKCS12");
+		else
+			kpc.setFileType("JKS");
+		kpc.setCredentialName(aliasEntry);
+		kpc.setUnlockPassword(unlockPassword);
+		checkError(run.security().credentials()
+				.postXmlAsOctetStream(kpc, ClientResponse.class));
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
new file mode 100644
index 0000000..9c375ad
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/Status.java
@@ -0,0 +1,36 @@
+package uk.org.taverna.server.client;
+
+/**
+ * States of a workflow run. They are {@link #Initialized Initialized},
+ * {@link #Operating Operating}, {@link #Stopped Stopped}, and
+ * {@link #Finished Finished}. Conceptually, there is also a
+ * <tt>Destroyed</tt> state, but the workflow run does not exist (and hence
+ * can't have its state queried or set) in that case.
+ * 
+ * @author Donal Fellows
+ */
+public enum Status {
+	/**
+	 * The workflow run has been created, but is not yet running. The run
+	 * will need to be manually moved to {@link #Operating Operating} when
+	 * ready.
+	 */
+	Initialized,
+	/**
+	 * The workflow run is going, reading input, generating output, etc.
+	 * Will eventually either move automatically to {@link #Finished
+	 * Finished} or can be moved manually to {@link #Stopped Stopped} (where
+	 * supported).
+	 */
+	Operating,
+	/**
+	 * The workflow run is paused, and will need to be moved back to
+	 * {@link #Operating Operating} manually.
+	 */
+	Stopped,
+	/**
+	 * The workflow run has ceased; data files will continue to exist until
+	 * the run is destroyed (which may be manual or automatic).
+	 */
+	Finished
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
new file mode 100644
index 0000000..7c0dcdd
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
@@ -0,0 +1,128 @@
+package uk.org.taverna.server.client;
+
+import static java.nio.file.Files.readAllBytes;
+import static org.taverna.server.client.wadl.TavernaServer.createClient;
+import static org.taverna.server.client.wadl.TavernaServer.root;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.taverna.server.client.wadl.TavernaServer.Root;
+
+import uk.org.taverna.server.client.generic.Capability;
+import uk.org.taverna.server.client.generic.TavernaRun;
+import uk.org.taverna.server.client.generic.VersionedElement;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+
+public class TavernaServer extends Connected {
+	final Root root;
+	private final URI location;
+	private final boolean authenticated;
+
+	TavernaServer(URI serviceRoot) {
+		root = root(createClient(), location = serviceRoot);
+		authenticated = false;
+	}
+
+	TavernaServer(URI serviceRoot, String username, String password) {
+		Client client = createClient();
+		client.addFilter(new HTTPBasicAuthFilter(username, password));
+		authenticated = true;
+		root = root(client, location = serviceRoot);
+	}
+
+	TavernaServer(TavernaServer service, String username, String password) {
+		Client client = createClient();
+		client.addFilter(new HTTPBasicAuthFilter(username, password));
+		authenticated = true;
+		root = root(client, location = service.location);
+		getServerVersionInfo();
+	}
+
+	public TavernaServer upgradeToAuth(String username, String password) {
+		if (authenticated)
+			throw new IllegalStateException("may only upgrade an unauthenticated connection");
+		return new TavernaServer(this, username, password);
+	}
+
+	public List<Capability> getCapabilities() {
+		return root.policy().capabilities().getAsCapabilitiesXml()
+				.getCapability();
+	}
+
+	public int getRunLimit() {
+		return root.policy().runLimit().getAsTextPlain(Integer.class);
+	}
+
+	public int getOperatingLimit() {
+		return root.policy().operatingLimit().getAsTextPlain(Integer.class);
+	}
+
+	public List<String> getPermittedWorkflows() {
+		return root.policy().permittedWorkflows().getAsPermittedWorkflowsXml()
+				.getWorkflow();
+	}
+
+	public List<Run> getExistingRuns() {
+		List<Run> runs = new ArrayList<>();
+		for (TavernaRun run : root.runs().getAsRunListXml().getRun())
+			runs.add(new Run(this, run.getValue()));
+		return runs;
+	}
+
+	public VersionedElement getServerVersionInfo() {
+		return root.getAsServerDescriptionXml();
+	}
+
+	private Run response2run(ClientResponse response) throws ClientException, ServerException {
+		checkError(response);
+		if (response.getClientResponseStatus().getStatusCode() == 201) {
+			String[] path = response.getLocation().getPath().split("/");
+			return new Run(this, path[path.length - 1]);
+		}
+		return null;
+	}
+
+	public Run createWorkflowRun(byte[] t2flowBytes) throws ClientException, ServerException {
+		return response2run(root.runs().postVndTavernaT2flowXmlAsOctetStream(
+				t2flowBytes, ClientResponse.class));
+	}
+
+	public Run createWorkflowRun(File t2flowFile) throws IOException, ClientException, ServerException {
+		return createWorkflowRun(readAllBytes(t2flowFile.toPath()));
+	}
+
+	public Run createWorkflowRun(URI t2flowUri) throws ClientException, ServerException {
+		return response2run(root.runs().postTextUriListAsOctetStream(
+				t2flowUri.toString(), ClientResponse.class));
+	}
+
+
+	public static class ClientException extends Exception {
+		private static final long serialVersionUID = 1L;
+
+		ClientException(String msg, Throwable cause) {
+			super(msg, cause);
+		}
+	}
+	public static class AuthorizationException extends ClientException {
+		private static final long serialVersionUID = 1L;
+
+		AuthorizationException(String msg, Throwable cause) {
+			super(msg, cause);
+		}
+	}
+	static class ServerException extends Exception {
+		private static final long serialVersionUID = 1L;
+
+		ServerException(String msg, Throwable cause) {
+			super(msg, cause);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
new file mode 100644
index 0000000..b00b075
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
@@ -0,0 +1,23 @@
+package uk.org.taverna.server.client;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TavernaServerConnectionFactory {
+	private Map<URI, TavernaServer> cache = new HashMap<>();
+
+	public synchronized TavernaServer connectNoAuth(URI uri) {
+		TavernaServer conn = cache.get(uri);
+		if (conn == null)
+			cache.put(uri, conn = new TavernaServer(uri));
+		return conn;
+	}
+
+	public TavernaServer connectAuth(URI uri, String username, String password) {
+		TavernaServer conn = new TavernaServer(uri, username, password);
+		// Force a check of the credentials by getting the server version
+		conn.getServerVersionInfo();
+		return conn;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java b/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
new file mode 100644
index 0000000..59e809d
--- /dev/null
+++ b/taverna-server-client/src/main/java/uk/org/taverna/server/client/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Implementation of a basic client for Taverna Server.
+ * @author Donal Fellows
+ */
+package uk.org.taverna.server.client;
\ No newline at end of file


[05/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css b/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
new file mode 100644
index 0000000..8b8afac
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
@@ -0,0 +1,563 @@
+/*!
+ * jQuery UI CSS Framework 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:after { clear: both; }
+.ui-helper-clearfix { zoom: 1; }
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*!
+ * jQuery UI CSS Framework 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=segoe%20ui,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=3px&bgColorHeader=f9f9f9&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=100&borderColorHeader=cccccc&fcHeader=e69700&iconColorHeader=5fa5e3&bgColorContent=eeeeee&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=0a82eb&bgColorDefault=1484e6&bgTextureDefault=08_diagonals_thick.png&bgImgOpacityDefault=22&borderColorDefault=ffffff&fcDefault=ffffff&iconColorDefault=fcdd4a&bgColorHover=2293f7&bgTextureHover=08_diagonals_thick.png&bgImgOpacityHover=26&borderColorHover=2293f7&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=e69700&bgTextureActive=08_diagonals_thick.png&bgImgOpacityActive=20&borderColorActive=e69700&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=c5ddfc&bgTextureHighlight=07_diagonals_small.png&bgImgOpacityHighlight=25&borderCol
 orHighlight=ffffff&fcHighlight=333333&iconColorHighlight=0b54d5&bgColorError=e69700&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=20&borderColorError=e69700&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=e6b900&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=e69700&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=20&thicknessShadow=0px&offsetTopShadow=6px&offsetLeftShadow=6px&cornerRadiusShadow=3px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: segoe ui, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: segoe ui, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #eeeeee url(ui-bg_inset-hard_100_eeeeee_1x100.png) 50% bottom repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #cccccc; background: #f9f9f9 url(ui-bg_highlight-soft_100_f9f9f9_1x100.png) 50% 50% repeat-x; color: #e69700; font-weight: bold; }
+.ui-widget-header a { color: #e69700; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #ffffff; background: #1484e6 url(ui-bg_diagonals-thick_22_1484e6_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #ffffff; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #2293f7; background: #2293f7 url(ui-bg_diagonals-thick_26_2293f7_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #e69700; background: #e69700 url(ui-bg_diagonals-thick_20_e69700_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ffffff; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #ffffff; background: #c5ddfc url(ui-bg_diagonals-small_25_c5ddfc_40x40.png) 50% 50% repeat; color: #333333; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #333333; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #e69700; background: #e69700 url(ui-bg_diagonals-thick_20_e69700_40x40.png) 50% 50% repeat; color: #ffffff; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(ui-icons_0a82eb_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(ui-icons_0a82eb_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(ui-icons_5fa5e3_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(ui-icons_fcdd4a_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(ui-icons_0b54d5_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; -khtml-border-top-left-radius: 3px; border-top-left-radius: 3px; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; -khtml-border-top-right-radius: 3px; border-top-right-radius: 3px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; -khtml-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; -khtml-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #e6b900 url(ui-bg_flat_0_e6b900_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: 6px 0 0 6px; padding: 0px; background: #e69700 url(ui-bg_flat_0_e69700_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 3px; -khtml-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; }/*!
+ * jQuery UI Resizable 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*!
+ * jQuery UI Selectable 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+/*!
+ * jQuery UI Accordion 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }
+/*!
+ * jQuery UI Autocomplete 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }	
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.23
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+	font-weight: normal;
+	margin: -1px;
+}
+/*!
+ * jQuery UI Button 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; } 
+button.ui-button-icons-only { width: 3.7em; } 
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4;  }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+/*!
+ * jQuery UI Dialog 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/*!
+ * jQuery UI Slider 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*!
+ * jQuery UI Tabs 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/*!
+ * jQuery UI Datepicker 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month, 
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+    position: absolute; /*must have*/
+    z-index: -1; /*must have*/
+    filter: mask(); /*must have*/
+    top: -4px; /*must have*/
+    left: -4px; /*must have*/
+    width: 200px; /*must have*/
+    height: 200px; /*must have*/
+}/*!
+ * jQuery UI Progressbar 1.8.23
+ *
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file


[14/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
new file mode 100644
index 0000000..61640bf
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+
+package org.taverna.server.master.notification;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jivesoftware.smack.Chat;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.MessageListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.packet.Message;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Send notifications by Jabber/XMPP.
+ * 
+ * @author Donal Fellows
+ */
+public class JabberDispatcher implements MessageDispatcher {
+	@Override
+	public String getName() {
+		return "xmpp";
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private XMPPConnection conn;
+	private String resource = "TavernaServer";
+	private String host = "";
+	private String user = "";
+	private String pass = "";
+
+	/**
+	 * @param resource
+	 *            The XMPP resource to use when connecting the server. This
+	 *            defaults to "<tt>TavernaServer</tt>".
+	 */
+	public void setResource(String resource) {
+		this.resource = resource;
+	}
+
+	/**
+	 * @param service
+	 *            The XMPP service URL.
+	 */
+	public void setHost(String service) {
+		if (service == null || service.trim().isEmpty()
+				|| service.trim().startsWith("$"))
+			this.host = "";
+		else
+			this.host = service.trim();
+	}
+
+	/**
+	 * @param user
+	 *            The user identity to use with the XMPP service.
+	 */
+	public void setUsername(String user) {
+		if (user == null || user.trim().isEmpty()
+				|| user.trim().startsWith("$"))
+			this.user = "";
+		else
+			this.user = user.trim();
+	}
+
+	/**
+	 * @param pass
+	 *            The password to use with the XMPP service.
+	 */
+	public void setPassword(String pass) {
+		if (pass == null || pass.trim().isEmpty()
+				|| pass.trim().startsWith("$"))
+			this.pass = "";
+		else
+			this.pass = pass.trim();
+	}
+
+	@PostConstruct
+	void setup() {
+		try {
+			if (host.isEmpty() || user.isEmpty() || pass.isEmpty()) {
+				log.info("disabling XMPP support; incomplete configuration");
+				conn = null;
+				return;
+			}
+			ConnectionConfiguration cfg = new ConnectionConfiguration(host);
+			cfg.setSendPresence(false);
+			XMPPConnection c = new XMPPConnection(cfg);
+			c.connect();
+			c.login(user, pass, resource);
+			conn = c;
+			log.info("connected to XMPP service <" + host + "> as user <"
+					+ user + ">");
+		} catch (Exception e) {
+			log.info("failed to connect to XMPP server", e);
+		}
+	}
+
+	@PreDestroy
+	public void close() {
+		if (conn != null)
+			conn.disconnect();
+		conn = null;
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return conn != null;
+	}
+
+	@Override
+	public void dispatch(TavernaRun ignored, String messageSubject,
+			String messageContent, String targetParameter) throws Exception {
+		Chat chat = conn.getChatManager().createChat(targetParameter,
+				new DroppingListener());
+		Message m = new Message();
+		m.addBody(null, messageContent);
+		m.setSubject(messageSubject);
+		chat.sendMessage(m);
+	}
+
+	static class DroppingListener implements MessageListener {
+		private Log log = LogFactory
+				.getLog("Taverna.Server.Notification.Jabber");
+
+		@Override
+		public void processMessage(Chat chat, Message message) {
+			if (log.isDebugEnabled())
+				log.debug("unexpectedly received XMPP message from <"
+						+ message.getFrom() + ">; ignoring");
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
new file mode 100644
index 0000000..bc0f60d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A common object for handling dispatch of event-driven messages.
+ * 
+ * @author Donal Fellows
+ */
+public class NotificationEngine {
+	private Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private Map<String, MessageDispatcher> dispatchers;
+	private List<MessageDispatcher> universalDispatchers;
+
+	/**
+	 * @param dispatchers
+	 *            The various dispatchers we want to install.
+	 */
+	@Required
+	public void setDispatchers(List<MessageDispatcher> dispatchers) {
+		this.dispatchers = new HashMap<>();
+		for (MessageDispatcher d : dispatchers)
+			this.dispatchers.put(d.getName(), d);
+	}
+
+	/**
+	 * @param dispatcherList
+	 *            A list of dispatch objects to always dispatch to.
+	 */
+	@Required
+	public void setUniversalDispatchers(List<MessageDispatcher> dispatcherList) {
+		this.universalDispatchers = dispatcherList;
+	}
+
+	private void dispatchToChosenTarget(TavernaRun originator, String scheme,
+			String target, Message message) throws Exception {
+		try {
+			MessageDispatcher d = dispatchers.get(scheme);
+			if (d != null && d.isAvailable())
+				d.dispatch(originator, message.getTitle(scheme),
+						message.getContent(scheme), target);
+			else
+				log.warn("no such notification dispatcher for " + scheme);
+		} catch (URISyntaxException e) {
+			// See if *someone* will handle the message
+			Exception e2 = null;
+			for (MessageDispatcher d : dispatchers.values())
+				try {
+					if (d.isAvailable()) {
+						d.dispatch(originator, message.getTitle(d.getName()),
+								message.getContent(d.getName()), scheme + ":"
+										+ target);
+						return;
+					}
+				} catch (Exception ex) {
+					if (log.isDebugEnabled())
+						log.debug("failed in pseudo-directed dispatch of "
+								+ scheme + ":" + target, ex);
+					e2 = ex;
+				}
+			if (e2 != null)
+				throw e2;
+		}
+	}
+
+	private void dispatchUniversally(TavernaRun originator, Message message)
+			throws Exception {
+		for (MessageDispatcher d : universalDispatchers)
+			try {
+				if (d.isAvailable())
+					d.dispatch(originator, message.getTitle(d.getName()),
+							message.getContent(d.getName()), null);
+			} catch (Exception e) {
+				log.warn("problem in universal dispatcher", e);
+			}
+	}
+
+	/**
+	 * Dispatch a message over the notification fabric.
+	 * 
+	 * @param originator
+	 *            What workflow run was the source of this message?
+	 * @param destination
+	 *            Where the message should get delivered to. The correct format
+	 *            of this is either as a URI of some form (where the scheme
+	 *            determines the dispatcher) or as an invalid URI in which case
+	 *            it is just tried against the possibilities to see if any
+	 *            succeeds.
+	 * @param subject
+	 *            The subject line of the message.
+	 * @param message
+	 *            The plain text body of the message.
+	 * @throws Exception
+	 *             If anything goes wrong with the dispatch process.
+	 */
+	public void dispatchMessage(TavernaRun originator, String destination,
+			Message message) throws Exception {
+		if (destination != null && !destination.trim().isEmpty()) {
+			try {
+				URI toURI = new URI(destination.trim());
+				dispatchToChosenTarget(originator, toURI.getScheme(),
+						toURI.getSchemeSpecificPart(), message);
+			} catch (URISyntaxException e) {
+				// Ignore
+			}
+		}
+		dispatchUniversally(originator, message);
+	}
+
+	/**
+	 * @return The message dispatchers that are actually available (i.e., not
+	 *         disabled by configuration somewhere).
+	 */
+	public List<String> listAvailableDispatchers() {
+		ArrayList<String> result = new ArrayList<>();
+		for (Map.Entry<String, MessageDispatcher> entry : dispatchers
+				.entrySet()) {
+			if (entry.getValue().isAvailable())
+				result.add(entry.getKey());
+		}
+		return result;
+	}
+
+	public interface Message {
+		String getContent(String type);
+
+		String getTitle(String type);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
new file mode 100644
index 0000000..c8d7ef6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Rate-limiting support. Some message fabrics simply should not be used to send
+ * a lot of messages.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class RateLimitedDispatcher implements MessageDispatcher {
+	/** Pre-configured logger. */
+	protected Log log = LogFactory.getLog("Taverna.Server.Notification");
+	private int cooldownSeconds;
+	private Map<String, DateTime> lastSend = new HashMap<>();
+
+	String valid(String value, String def) {
+		if (value == null || value.trim().isEmpty()
+				|| value.trim().startsWith("${"))
+			return def;
+		else
+			return value.trim();
+	}
+
+	/**
+	 * Set how long must elapse between updates to the status of any particular
+	 * user. Calls before that time are just silently dropped.
+	 * 
+	 * @param cooldownSeconds
+	 *            Time to elapse, in seconds.
+	 */
+	public void setCooldownSeconds(int cooldownSeconds) {
+		this.cooldownSeconds = cooldownSeconds;
+	}
+
+	/**
+	 * Test whether the rate limiter allows the given user to send a message.
+	 * 
+	 * @param who
+	 *            Who wants to send the message?
+	 * @return <tt>true</tt> iff they are permitted.
+	 */
+	protected boolean isSendAllowed(String who) {
+		DateTime now = new DateTime();
+		synchronized (lastSend) {
+			DateTime last = lastSend.get(who);
+			if (last != null) {
+				if (!now.isAfter(last.plusSeconds(cooldownSeconds)))
+					return false;
+			}
+			lastSend.put(who, now);
+		}
+		return true;
+	}
+
+	@Override
+	public void dispatch(TavernaRun ignored, String messageSubject,
+			String messageContent, String target) throws Exception {
+		if (isSendAllowed(target))
+			dispatch(messageSubject, messageContent, target);
+	}
+
+	/**
+	 * Dispatch a message to a recipient that doesn't care what produced it.
+	 * 
+	 * @param messageSubject
+	 *            The subject of the message to send.
+	 * @param messageContent
+	 *            The plain-text content of the message to send.
+	 * @param target
+	 *            A description of where it is to go.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public abstract void dispatch(String messageSubject, String messageContent,
+			String target) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
new file mode 100644
index 0000000..5553141
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification;
+
+import static org.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Dispatch termination messages via SMS.
+ * 
+ * @author Donal Fellows
+ */
+public class SMSDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "sms";
+	}
+
+	private CloseableHttpClient client;
+	private URI service;
+	private String user = "", pass = "";
+	private String usernameField = "username", passwordField = "password",
+			destinationField = "to", messageField = "text";
+
+	/**
+	 * @param usernameField
+	 *            The name of the field that conveys the sending username; this
+	 *            is the <i>server</i>'s identity.
+	 */
+	@Required
+	public void setUsernameField(String usernameField) {
+		this.usernameField = usernameField;
+	}
+
+	/**
+	 * @param passwordField
+	 *            The field holding the password to authenticate the server to
+	 *            the SMS gateway.
+	 */
+	@Required
+	public void setPasswordField(String passwordField) {
+		this.passwordField = passwordField;
+	}
+
+	/**
+	 * @param destinationField
+	 *            The field holding the number to send the SMS to.
+	 */
+	@Required
+	public void setDestinationField(String destinationField) {
+		this.destinationField = destinationField;
+	}
+
+	/**
+	 * @param messageField
+	 *            The field holding the plain-text message to send.
+	 */
+	@Required
+	public void setMessageField(String messageField) {
+		this.messageField = messageField;
+	}
+
+	public void setService(String serviceURL) {
+		String s = valid(serviceURL, "");
+		if (s.isEmpty()) {
+			log.warn("did not get sms.service from servlet config; using default ("
+					+ SMS_GATEWAY_URL + ")");
+			s = SMS_GATEWAY_URL;
+		}
+		try {
+			service = new URI(s);
+		} catch (URISyntaxException e) {
+			service = null;
+		}
+	}
+
+	public void setUser(String user) {
+		this.user = valid(user, "");
+	}
+
+	public void setPassword(String pass) {
+		this.pass = valid(pass, "");
+	}
+
+	@PostConstruct
+	void init() {
+		client = HttpClientBuilder.create().build();
+	}
+
+	@PreDestroy
+	void close() throws IOException {
+		try {
+			if (client != null)
+				client.close();
+		} finally {
+			client = null;
+		}
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return service != null && !user.isEmpty() && !pass.isEmpty();
+	}
+
+	@Override
+	public void dispatch(String messageSubject, String messageContent,
+			String targetParameter) throws Exception {
+		// Sanity check
+		if (!targetParameter.matches("[^0-9]+"))
+			throw new Exception("invalid phone number");
+
+		if (!isSendAllowed("anyone"))
+			return;
+
+		// Build the message to send
+		List<NameValuePair> params = new ArrayList<>();
+		params.add(new BasicNameValuePair(usernameField, user));
+		params.add(new BasicNameValuePair(passwordField, pass));
+		params.add(new BasicNameValuePair(destinationField, targetParameter));
+		params.add(new BasicNameValuePair(messageField, messageContent));
+
+		// Send the message
+		HttpPost post = new HttpPost(service);
+		post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
+		HttpResponse response = client.execute(post);
+
+		// Log the response
+		HttpEntity entity = response.getEntity();
+		if (entity != null)
+			try (BufferedReader e = new BufferedReader(new InputStreamReader(
+					entity.getContent()))) {
+				log.info(e.readLine());
+			}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
new file mode 100644
index 0000000..8ee4815
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification;
+
+import java.util.Properties;
+
+import twitter4j.Twitter;
+import twitter4j.TwitterFactory;
+import twitter4j.conf.Configuration;
+import twitter4j.conf.PropertyConfiguration;
+import twitter4j.auth.AuthorizationFactory;
+
+/**
+ * Super simple-minded twitter dispatcher. You need to tell it your consumer key
+ * and secret as part of the connection parameters, for example via a dispatcher
+ * URN of "<tt>twitter:fred:bloggs</tt>" where <tt>fred</tt> is the key and
+ * <tt>bloggs</tt> is the secret.
+ * 
+ * @author Donal Fellows
+ */
+public class TwitterDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "twitter";
+	}
+
+	public static final int MAX_MESSAGE_LENGTH = 140;
+	public static final char ELLIPSIS = '\u2026';
+
+	private String token = "";
+	private String secret = "";
+
+	public void setAccessToken(String token) {
+		this.token = valid(token, "");
+	}
+
+	public void setAccessSecret(String secret) {
+		this.secret = valid(secret, "");
+	}
+
+	private Properties getConfig() throws NotConfiguredException {
+		if (token.isEmpty() || secret.isEmpty())
+			throw new NotConfiguredException();
+		Properties p = new Properties();
+		p.setProperty(ACCESS_TOKEN_PROP, token);
+		p.setProperty(ACCESS_SECRET_PROP, secret);
+		return p;
+	}
+
+	public static final String ACCESS_TOKEN_PROP = "oauth.accessToken";
+	public static final String ACCESS_SECRET_PROP = "oauth.accessTokenSecret";
+
+	private Twitter getTwitter(String key, String secret) throws Exception {
+		if (key.isEmpty() || secret.isEmpty())
+			throw new NoCredentialsException();
+
+		Properties p = getConfig();
+		p.setProperty("oauth.consumerKey", key);
+		p.setProperty("oauth.consumerSecret", secret);
+
+		Configuration config = new PropertyConfiguration(p);
+		TwitterFactory factory = new TwitterFactory(config);
+		Twitter t = factory.getInstance(AuthorizationFactory
+				.getInstance(config));
+		// Verify that we can connect!
+		t.getOAuthAccessToken();
+		return t;
+	}
+
+	// TODO: Get secret from credential manager
+	@Override
+	public void dispatch(String messageSubject, String messageContent,
+			String targetParameter) throws Exception {
+		// messageSubject ignored
+		String[] target = targetParameter.split(":", 2);
+		if (target == null || target.length != 2)
+			throw new Exception("missing consumer key or secret");
+		String who = target[0];
+		if (!isSendAllowed(who))
+			return;
+		Twitter twitter = getTwitter(who, target[1]);
+
+		if (messageContent.length() > MAX_MESSAGE_LENGTH)
+			messageContent = messageContent
+					.substring(0, MAX_MESSAGE_LENGTH - 1) + ELLIPSIS;
+		twitter.updateStatus(messageContent);
+	}
+
+	@Override
+	public boolean isAvailable() {
+		try {
+			// Try to create the configuration and push it through as far as
+			// confirming that we can build an access object (even if it isn't
+			// bound to a user)
+			new TwitterFactory(new PropertyConfiguration(getConfig()))
+					.getInstance();
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Indicates that the dispatcher has not been configured with service
+	 * credentials.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@SuppressWarnings("serial")
+	public static class NotConfiguredException extends Exception {
+		NotConfiguredException() {
+			super("not configured with xAuth key and secret; "
+					+ "dispatch not possible");
+		}
+	}
+
+	/**
+	 * Indicates that the user did not supply their credentials.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@SuppressWarnings("serial")
+	public static class NoCredentialsException extends Exception {
+		NoCredentialsException() {
+			super("no consumer key and secret present; "
+					+ "dispatch not possible");
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
new file mode 100644
index 0000000..e5beaeb
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification.atom;
+
+import static java.lang.String.format;
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.common.Uri.secure;
+
+import java.net.URI;
+import java.util.Date;
+
+import javax.annotation.security.RolesAllowed;
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.web.context.ServletContextAware;
+import org.taverna.server.master.TavernaServerSupport;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.rest.TavernaServerREST.EventFeed;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * Simple REST handler that allows an Atom feed to be served up of events
+ * generated by workflow runs.
+ * 
+ * @author Donal Fellows
+ */
+public class AtomFeed implements EventFeed, UriBuilderFactory,
+		ServletContextAware {
+	/**
+	 * The name of a parameter that states what address we should claim that the
+	 * feed's internally-generated URIs are relative to. If not set, a default
+	 * will be guessed.
+	 */
+	public static final String PREFERRED_URI_PARAM = "taverna.preferredUserUri";
+	private EventDAO eventSource;
+	private TavernaServerSupport support;
+	private URI baseURI;
+	private Abdera abdera;
+	private String feedLanguage = "en";
+	private String uuid = randomUUID().toString();
+
+	@Required
+	public void setEventSource(EventDAO eventSource) {
+		this.eventSource = eventSource;
+	}
+
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	public void setFeedLanguage(String language) {
+		this.feedLanguage = language;
+	}
+
+	public String getFeedLanguage() {
+		return feedLanguage;
+	}
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		this.abdera = abdera;
+	}
+
+	@Override
+	@CallCounted
+	@RolesAllowed(USER)
+	public Feed getFeed(UriInfo ui) {
+		Feed feed = abdera.getFactory().newFeed();
+		feed.setTitle("events relating to workflow runs").setLanguage(
+				feedLanguage);
+		String user = support.getPrincipal().toString()
+				.replaceAll("[^A-Za-z0-9]+", "");
+		feed.setId(format("urn:taverna-server:%s:%s", uuid, user));
+		org.joda.time.DateTime modification = null;
+		for (Event e : eventSource.getEvents(support.getPrincipal())) {
+			if (modification == null || e.getPublished().isAfter(modification))
+				modification = e.getPublished();
+			feed.addEntry(e.getEntry(abdera, feedLanguage));
+		}
+		if (modification == null)
+			feed.setUpdated(new Date());
+		else
+			feed.setUpdated(modification.toDate());
+		feed.addLink(ui.getAbsolutePath().toASCIIString(), "self");
+		return feed;
+	}
+
+	@Override
+	@CallCounted
+	@RolesAllowed(USER)
+	public Entry getEvent(String id) {
+		return eventSource.getEvent(support.getPrincipal(), id).getEntry(
+				abdera, feedLanguage);
+	}
+
+	@Override
+	public UriBuilder getRunUriBuilder(TavernaRun run) {
+		return secure(fromUri(getBaseUriBuilder().path("runs/{uuid}").build(
+				run.getId())));
+	}
+
+	@Override
+	public UriBuilder getBaseUriBuilder() {
+		return secure(fromUri(baseURI));
+	}
+
+	@Override
+	public String resolve(String uri) {
+		if (uri == null)
+			return null;
+		return secure(baseURI, uri).toString();
+	}
+
+	@Override
+	public void setServletContext(ServletContext servletContext) {
+		String base = servletContext.getInitParameter(PREFERRED_URI_PARAM);
+		if (base == null)
+			base = servletContext.getContextPath() + "/rest";
+		baseURI = URI.create(base);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
new file mode 100644
index 0000000..825029d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification.atom;
+
+import static java.util.UUID.randomUUID;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Date;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Index;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Entry;
+import org.joda.time.DateTime;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Parent class of all events that may appear on the feed for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+@PersistenceCapable(schema = "ATOM", table = "EVENTS")
+@Queries({
+		@Query(name = "eventsForUser", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? ORDER BY published DESC", resultClass = String.class),
+		@Query(name = "eventForUserAndId", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? AND id = ?", resultClass = String.class),
+		@Query(name = "eventsFromBefore", language = "SQL", value = "SELECT id FROM ATOM.EVENTS where published < ?", resultClass = String.class) })
+public class Event implements Serializable {
+	@Persistent(primaryKey = "true")
+	@Column(length = 48)
+	private String id;
+	@Persistent
+	private String owner;
+	@Persistent
+	@Index
+	private Date published;
+	@Persistent
+	private String message;
+	@Persistent
+	private String title;
+	@Persistent
+	private String link;
+
+	Event() {
+	}
+
+	/**
+	 * Initialise the identity of this event and the point at which it was
+	 * published.
+	 * 
+	 * @param idPrefix
+	 *            A prefix for the identity of this event.
+	 * @param owner
+	 *            Who is the owner of this event.
+	 */
+	Event(String idPrefix, URI workflowLink, UsernamePrincipal owner,
+			String title, String message) {
+		id = idPrefix + "." + randomUUID().toString();
+		published = new Date();
+		this.owner = owner.getName();
+		this.title = title;
+		this.message = message;
+		this.link = workflowLink.toASCIIString();
+	}
+
+	public final String getId() {
+		return id;
+	}
+
+	public final String getOwner() {
+		return owner;
+	}
+
+	public final DateTime getPublished() {
+		return new DateTime(published);
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public String getLink() {
+		return link;
+	}
+
+	public Entry getEntry(Abdera abdera, String language) {
+		Entry entry = abdera.getFactory().newEntry();
+		entry.setId(id);
+		entry.setPublished(published);
+		entry.addAuthor(owner).setLanguage(language);
+		entry.setUpdated(published);
+		entry.setTitle(title).setLanguage(language);
+		entry.addLink(link, "related").setTitle("workflow run");
+		entry.setContent(message).setLanguage(language);
+		return entry;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
new file mode 100644
index 0000000..56f25ff
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification.atom;
+
+import static java.lang.Thread.interrupted;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PreDestroy;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.MessageDispatcher;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The database interface that supports the event feed.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class EventDAO extends JDOSupport<Event> implements MessageDispatcher {
+	public EventDAO() {
+		super(Event.class);
+	}
+
+	@Override
+	public String getName() {
+		return "atom";
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Atom");
+	private UriBuilderFactory ubf;
+	private int expiryAgeDays;
+
+	@Required
+	public void setExpiryAgeDays(int expiryAgeDays) {
+		this.expiryAgeDays = expiryAgeDays;
+	}
+
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory ubf) {
+		this.ubf = ubf;
+	}
+
+	/**
+	 * Get the given user's list of events.
+	 * 
+	 * @param user
+	 *            The identity of the user to get the events for.
+	 * @return A copy of the list of events currently known about.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public List<Event> getEvents(@Nonnull UsernamePrincipal user) {
+		@SuppressWarnings("unchecked")
+		List<String> ids = (List<String>) namedQuery("eventsForUser").execute(
+				user.getName());
+		if (log.isDebugEnabled())
+			log.debug("found " + ids.size() + " events for user " + user);
+
+		List<Event> result = new ArrayList<>();
+		for (String id : ids) {
+			Event event = getById(id);
+			result.add(detach(event));
+		}
+		return result;
+	}
+
+	/**
+	 * Get a particular event.
+	 * 
+	 * @param user
+	 *            The identity of the user to get the event for.
+	 * @param id
+	 *            The handle of the event to look up.
+	 * @return A copy of the event.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public Event getEvent(@Nonnull UsernamePrincipal user, @Nonnull String id) {
+		@SuppressWarnings("unchecked")
+		List<String> ids = (List<String>) namedQuery("eventForUserAndId")
+				.execute(user.getName(), id);
+		if (log.isDebugEnabled())
+			log.debug("found " + ids.size() + " events for user " + user
+					+ " with id = " + id);
+
+		if (ids.size() != 1)
+			throw new IllegalArgumentException("no such id");
+		return detach(getById(ids.get(0)));
+	}
+
+	/**
+	 * Delete a particular event.
+	 * 
+	 * @param id
+	 *            The identifier of the event to delete.
+	 */
+	@WithinSingleTransaction
+	public void deleteEventById(@Nonnull String id) {
+		delete(getById(id));
+	}
+
+	/**
+	 * Delete all events that have expired.
+	 */
+	@WithinSingleTransaction
+	public void deleteExpiredEvents() {
+		Date death = new DateTime().plusDays(-expiryAgeDays).toDate();
+		death = new Timestamp(death.getTime()); // UGLY SQL HACK
+
+		@SuppressWarnings("unchecked")
+		List<String> ids = (List<String>) namedQuery("eventsFromBefore")
+				.execute(death);
+		if (log.isDebugEnabled() && !ids.isEmpty())
+			log.debug("found " + ids.size()
+					+ " events to be squelched (older than " + death + ")");
+
+		for (String id : ids)
+			delete(getById(id));
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return true;
+	}
+
+	private BlockingQueue<Event> insertQueue = new ArrayBlockingQueue<>(16);
+
+	@Override
+	public void dispatch(TavernaRun originator, String messageSubject,
+			String messageContent, String targetParameter) throws Exception {
+		insertQueue.put(new Event("finish", ubf.getRunUriBuilder(originator)
+				.build(), originator.getSecurityContext().getOwner(),
+				messageSubject, messageContent));
+	}
+
+	public void started(TavernaRun originator, String messageSubject,
+			String messageContent) throws InterruptedException {
+		insertQueue.put(new Event("start", ubf.getRunUriBuilder(originator)
+				.build(), originator.getSecurityContext().getOwner(),
+				messageSubject, messageContent));
+	}
+
+	private Thread eventDaemon;
+	private boolean shuttingDown = false;
+
+	@Required
+	public void setSelf(final EventDAO dao) {
+		eventDaemon = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					while (!shuttingDown && !interrupted()) {
+						transferEvents(dao, new ArrayList<Event>(
+								asList(insertQueue.take())));
+						sleep(5000);
+					}
+				} catch (InterruptedException e) {
+				} finally {
+					transferEvents(dao, new ArrayList<Event>());
+				}
+			}
+		}, "ATOM event daemon");
+		eventDaemon.setContextClassLoader(null);
+		eventDaemon.setDaemon(true);
+		eventDaemon.start();
+	}
+
+	private void transferEvents(EventDAO dao, List<Event> e) {
+		insertQueue.drainTo(e);
+		dao.storeEvents(e);
+	}
+
+	@PreDestroy
+	void stopDaemon() {
+		shuttingDown = true;
+		if (eventDaemon != null)
+			eventDaemon.interrupt();
+	}
+
+	@WithinSingleTransaction
+	protected void storeEvents(List<Event> events) {
+		for (Event e : events)
+			persist(e);
+		log.info("stored " + events.size() + " notification events");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
new file mode 100644
index 0000000..9cc592d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the Atom feed implementation within Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = FEED, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.notification.atom;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
new file mode 100644
index 0000000..979066a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * The notification fabric and implementations of notification dispatchers
+ * that support subscription.
+ */
+package org.taverna.server.master.notification;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
new file mode 100644
index 0000000..17bfd03
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/package-info.java
@@ -0,0 +1,11 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * The core of the implementation of Taverna Server, including the
+ * implementations of the SOAP and REST interfaces.
+ */
+package org.taverna.server.master;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
new file mode 100644
index 0000000..b0819a5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+
+/**
+ * Miscellaneous content type constants.
+ * 
+ * @author Donal Fellows
+ */
+interface ContentTypes {
+	static final String URI_LIST = "text/uri-list";
+	static final String ZIP = "application/zip";
+	static final String TEXT = TEXT_PLAIN;
+	static final String XML = APPLICATION_XML;
+	static final String JSON = APPLICATION_JSON;
+	static final String BYTES = APPLICATION_OCTET_STREAM;
+	static final String ATOM = APPLICATION_ATOM_XML;
+	static final String ROBUNDLE = "application/vnd.wf4ever.robundle+zip";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
new file mode 100644
index 0000000..e01d1c4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
@@ -0,0 +1,61 @@
+/*
+ * 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.Uri.secure;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+
+/**
+ * The result of a RESTful operation to list the contents of a directory. Done
+ * with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement
+@XmlType(name = "DirectoryContents")
+@XmlSeeAlso(MakeOrUpdateDirEntry.class)
+public class DirectoryContents {
+	/**
+	 * The contents of the directory.
+	 */
+	@XmlElementRef
+	public List<DirEntryReference> contents;
+
+	/**
+	 * Make an empty directory description. Required for JAXB.
+	 */
+	public DirectoryContents() {
+		contents = new ArrayList<>();
+	}
+
+	/**
+	 * Make a directory description.
+	 * 
+	 * @param ui
+	 *            The factory for URIs.
+	 * @param collection
+	 *            The real directory contents that we are to describe.
+	 */
+	public DirectoryContents(UriInfo ui, Collection<DirectoryEntry> collection) {
+		contents = new ArrayList<>();
+		UriBuilder ub = secure(ui).path("{filename}");
+		for (DirectoryEntry e : collection)
+			contents.add(DirEntryReference.newInstance(ub, e));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
new file mode 100644
index 0000000..74269c1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+import static javax.ws.rs.core.Response.ok;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Representation of a segment of a file to be read by JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+public class FileSegment {
+	/** The file to read a segment of. */
+	public final File file;
+	/** The offset of the first byte of the segment to read. */
+	public Integer from;
+	/** The offset of the first byte after the segment to read. */
+	public Integer to;
+
+	/**
+	 * Parse the HTTP Range header and determine what exact range of the file to
+	 * read.
+	 * 
+	 * @param f
+	 *            The file this refers to
+	 * @param range
+	 *            The content of the Range header.
+	 * @throws FilesystemAccessException
+	 *             If we can't determine the length of the file (shouldn't
+	 *             happen).
+	 */
+	public FileSegment(File f, String range) throws FilesystemAccessException {
+		file = f;
+		Matcher m = Pattern.compile("^\\s*bytes=(\\d*)-(\\d*)\\s*$").matcher(
+				range);
+		if (m.matches()) {
+			if (!m.group(1).isEmpty())
+				from = Integer.valueOf(m.group(1));
+			if (!m.group(2).isEmpty())
+				to = Integer.valueOf(m.group(2)) + 1;
+			int size = (int) f.getSize();
+			if (from == null) {
+				from = size - to;
+				to = size;
+			} else if (to == null)
+				to = size;
+			else if (to > size)
+				to = size;
+		}
+	}
+
+	/**
+	 * Convert to a response, as per RFC 2616.
+	 * 
+	 * @param type
+	 *            The expected type of the data.
+	 * @return A JAX-RS response.
+	 */
+	public Response toResponse(MediaType type) {
+		if (from == null && to == null)
+			return ok(file).type(type).build();
+		if (from >= to)
+			return ok("Requested range not satisfiable").status(416).build();
+		return ok(this).status(206).type(type).build();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
new file mode 100644
index 0000000..b9b4718
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+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/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
new file mode 100644
index 0000000..7a072be
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+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/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
new file mode 100644
index 0000000..0138f88
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+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/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
new file mode 100644
index 0000000..ea2f776
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+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/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
new file mode 100644
index 0000000..faed19d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
@@ -0,0 +1,355 @@
+/*
+ * 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.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;
+	}
+}


[29/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css b/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
deleted file mode 100644
index 8b8afac..0000000
--- a/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.css
+++ /dev/null
@@ -1,563 +0,0 @@
-/*!
- * jQuery UI CSS Framework 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
-/* Layout helpers
-----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
-.ui-helper-clearfix:after { clear: both; }
-.ui-helper-clearfix { zoom: 1; }
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
-
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
-
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
-
-
-/*!
- * jQuery UI CSS Framework 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=segoe%20ui,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=3px&bgColorHeader=f9f9f9&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=100&borderColorHeader=cccccc&fcHeader=e69700&iconColorHeader=5fa5e3&bgColorContent=eeeeee&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=0a82eb&bgColorDefault=1484e6&bgTextureDefault=08_diagonals_thick.png&bgImgOpacityDefault=22&borderColorDefault=ffffff&fcDefault=ffffff&iconColorDefault=fcdd4a&bgColorHover=2293f7&bgTextureHover=08_diagonals_thick.png&bgImgOpacityHover=26&borderColorHover=2293f7&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=e69700&bgTextureActive=08_diagonals_thick.png&bgImgOpacityActive=20&borderColorActive=e69700&fcActive=ffffff&iconColorActive=ffffff&bgColorHighlight=c5ddfc&bgTextureHighlight=07_diagonals_small.png&bgImgOpacityHighlight=25&borderCol
 orHighlight=ffffff&fcHighlight=333333&iconColorHighlight=0b54d5&bgColorError=e69700&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=20&borderColorError=e69700&fcError=ffffff&iconColorError=ffffff&bgColorOverlay=e6b900&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=e69700&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=20&thicknessShadow=0px&offsetTopShadow=6px&offsetLeftShadow=6px&cornerRadiusShadow=3px
- */
-
-
-/* Component containers
-----------------------------------*/
-.ui-widget { font-family: segoe ui, Arial, sans-serif; font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: segoe ui, Arial, sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #aaaaaa; background: #eeeeee url(ui-bg_inset-hard_100_eeeeee_1x100.png) 50% bottom repeat-x; color: #222222; }
-.ui-widget-content a { color: #222222; }
-.ui-widget-header { border: 1px solid #cccccc; background: #f9f9f9 url(ui-bg_highlight-soft_100_f9f9f9_1x100.png) 50% 50% repeat-x; color: #e69700; font-weight: bold; }
-.ui-widget-header a { color: #e69700; }
-
-/* Interaction states
-----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #ffffff; background: #1484e6 url(ui-bg_diagonals-thick_22_1484e6_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #ffffff; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #2293f7; background: #2293f7 url(ui-bg_diagonals-thick_26_2293f7_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #e69700; background: #e69700 url(ui-bg_diagonals-thick_20_e69700_40x40.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ffffff; text-decoration: none; }
-.ui-widget :active { outline: none; }
-
-/* Interaction Cues
-----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #ffffff; background: #c5ddfc url(ui-bg_diagonals-small_25_c5ddfc_40x40.png) 50% 50% repeat; color: #333333; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #333333; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #e69700; background: #e69700 url(ui-bg_diagonals-thick_20_e69700_40x40.png) 50% 50% repeat; color: #ffffff; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
-
-/* Icons
-----------------------------------*/
-
-/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(ui-icons_0a82eb_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(ui-icons_0a82eb_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(ui-icons_5fa5e3_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(ui-icons_fcdd4a_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(ui-icons_0b54d5_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
-
-/* positioning */
-.ui-icon-carat-1-n { background-position: 0 0; }
-.ui-icon-carat-1-ne { background-position: -16px 0; }
-.ui-icon-carat-1-e { background-position: -32px 0; }
-.ui-icon-carat-1-se { background-position: -48px 0; }
-.ui-icon-carat-1-s { background-position: -64px 0; }
-.ui-icon-carat-1-sw { background-position: -80px 0; }
-.ui-icon-carat-1-w { background-position: -96px 0; }
-.ui-icon-carat-1-nw { background-position: -112px 0; }
-.ui-icon-carat-2-n-s { background-position: -128px 0; }
-.ui-icon-carat-2-e-w { background-position: -144px 0; }
-.ui-icon-triangle-1-n { background-position: 0 -16px; }
-.ui-icon-triangle-1-ne { background-position: -16px -16px; }
-.ui-icon-triangle-1-e { background-position: -32px -16px; }
-.ui-icon-triangle-1-se { background-position: -48px -16px; }
-.ui-icon-triangle-1-s { background-position: -64px -16px; }
-.ui-icon-triangle-1-sw { background-position: -80px -16px; }
-.ui-icon-triangle-1-w { background-position: -96px -16px; }
-.ui-icon-triangle-1-nw { background-position: -112px -16px; }
-.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
-.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
-.ui-icon-arrow-1-n { background-position: 0 -32px; }
-.ui-icon-arrow-1-ne { background-position: -16px -32px; }
-.ui-icon-arrow-1-e { background-position: -32px -32px; }
-.ui-icon-arrow-1-se { background-position: -48px -32px; }
-.ui-icon-arrow-1-s { background-position: -64px -32px; }
-.ui-icon-arrow-1-sw { background-position: -80px -32px; }
-.ui-icon-arrow-1-w { background-position: -96px -32px; }
-.ui-icon-arrow-1-nw { background-position: -112px -32px; }
-.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
-.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
-.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
-.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
-.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
-.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
-.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
-.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
-.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
-.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
-.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
-.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
-.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
-.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
-.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
-.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
-.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
-.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
-.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
-.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.ui-icon-arrow-4 { background-position: 0 -80px; }
-.ui-icon-arrow-4-diag { background-position: -16px -80px; }
-.ui-icon-extlink { background-position: -32px -80px; }
-.ui-icon-newwin { background-position: -48px -80px; }
-.ui-icon-refresh { background-position: -64px -80px; }
-.ui-icon-shuffle { background-position: -80px -80px; }
-.ui-icon-transfer-e-w { background-position: -96px -80px; }
-.ui-icon-transferthick-e-w { background-position: -112px -80px; }
-.ui-icon-folder-collapsed { background-position: 0 -96px; }
-.ui-icon-folder-open { background-position: -16px -96px; }
-.ui-icon-document { background-position: -32px -96px; }
-.ui-icon-document-b { background-position: -48px -96px; }
-.ui-icon-note { background-position: -64px -96px; }
-.ui-icon-mail-closed { background-position: -80px -96px; }
-.ui-icon-mail-open { background-position: -96px -96px; }
-.ui-icon-suitcase { background-position: -112px -96px; }
-.ui-icon-comment { background-position: -128px -96px; }
-.ui-icon-person { background-position: -144px -96px; }
-.ui-icon-print { background-position: -160px -96px; }
-.ui-icon-trash { background-position: -176px -96px; }
-.ui-icon-locked { background-position: -192px -96px; }
-.ui-icon-unlocked { background-position: -208px -96px; }
-.ui-icon-bookmark { background-position: -224px -96px; }
-.ui-icon-tag { background-position: -240px -96px; }
-.ui-icon-home { background-position: 0 -112px; }
-.ui-icon-flag { background-position: -16px -112px; }
-.ui-icon-calendar { background-position: -32px -112px; }
-.ui-icon-cart { background-position: -48px -112px; }
-.ui-icon-pencil { background-position: -64px -112px; }
-.ui-icon-clock { background-position: -80px -112px; }
-.ui-icon-disk { background-position: -96px -112px; }
-.ui-icon-calculator { background-position: -112px -112px; }
-.ui-icon-zoomin { background-position: -128px -112px; }
-.ui-icon-zoomout { background-position: -144px -112px; }
-.ui-icon-search { background-position: -160px -112px; }
-.ui-icon-wrench { background-position: -176px -112px; }
-.ui-icon-gear { background-position: -192px -112px; }
-.ui-icon-heart { background-position: -208px -112px; }
-.ui-icon-star { background-position: -224px -112px; }
-.ui-icon-link { background-position: -240px -112px; }
-.ui-icon-cancel { background-position: 0 -128px; }
-.ui-icon-plus { background-position: -16px -128px; }
-.ui-icon-plusthick { background-position: -32px -128px; }
-.ui-icon-minus { background-position: -48px -128px; }
-.ui-icon-minusthick { background-position: -64px -128px; }
-.ui-icon-close { background-position: -80px -128px; }
-.ui-icon-closethick { background-position: -96px -128px; }
-.ui-icon-key { background-position: -112px -128px; }
-.ui-icon-lightbulb { background-position: -128px -128px; }
-.ui-icon-scissors { background-position: -144px -128px; }
-.ui-icon-clipboard { background-position: -160px -128px; }
-.ui-icon-copy { background-position: -176px -128px; }
-.ui-icon-contact { background-position: -192px -128px; }
-.ui-icon-image { background-position: -208px -128px; }
-.ui-icon-video { background-position: -224px -128px; }
-.ui-icon-script { background-position: -240px -128px; }
-.ui-icon-alert { background-position: 0 -144px; }
-.ui-icon-info { background-position: -16px -144px; }
-.ui-icon-notice { background-position: -32px -144px; }
-.ui-icon-help { background-position: -48px -144px; }
-.ui-icon-check { background-position: -64px -144px; }
-.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
-.ui-icon-pin-w { background-position: -128px -144px; }
-.ui-icon-pin-s { background-position: -144px -144px; }
-.ui-icon-play { background-position: 0 -160px; }
-.ui-icon-pause { background-position: -16px -160px; }
-.ui-icon-seek-next { background-position: -32px -160px; }
-.ui-icon-seek-prev { background-position: -48px -160px; }
-.ui-icon-seek-end { background-position: -64px -160px; }
-.ui-icon-seek-start { background-position: -80px -160px; }
-/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
-.ui-icon-seek-first { background-position: -80px -160px; }
-.ui-icon-stop { background-position: -96px -160px; }
-.ui-icon-eject { background-position: -112px -160px; }
-.ui-icon-volume-off { background-position: -128px -160px; }
-.ui-icon-volume-on { background-position: -144px -160px; }
-.ui-icon-power { background-position: 0 -176px; }
-.ui-icon-signal-diag { background-position: -16px -176px; }
-.ui-icon-signal { background-position: -32px -176px; }
-.ui-icon-battery-0 { background-position: -48px -176px; }
-.ui-icon-battery-1 { background-position: -64px -176px; }
-.ui-icon-battery-2 { background-position: -80px -176px; }
-.ui-icon-battery-3 { background-position: -96px -176px; }
-.ui-icon-circle-plus { background-position: 0 -192px; }
-.ui-icon-circle-minus { background-position: -16px -192px; }
-.ui-icon-circle-close { background-position: -32px -192px; }
-.ui-icon-circle-triangle-e { background-position: -48px -192px; }
-.ui-icon-circle-triangle-s { background-position: -64px -192px; }
-.ui-icon-circle-triangle-w { background-position: -80px -192px; }
-.ui-icon-circle-triangle-n { background-position: -96px -192px; }
-.ui-icon-circle-arrow-e { background-position: -112px -192px; }
-.ui-icon-circle-arrow-s { background-position: -128px -192px; }
-.ui-icon-circle-arrow-w { background-position: -144px -192px; }
-.ui-icon-circle-arrow-n { background-position: -160px -192px; }
-.ui-icon-circle-zoomin { background-position: -176px -192px; }
-.ui-icon-circle-zoomout { background-position: -192px -192px; }
-.ui-icon-circle-check { background-position: -208px -192px; }
-.ui-icon-circlesmall-plus { background-position: 0 -208px; }
-.ui-icon-circlesmall-minus { background-position: -16px -208px; }
-.ui-icon-circlesmall-close { background-position: -32px -208px; }
-.ui-icon-squaresmall-plus { background-position: -48px -208px; }
-.ui-icon-squaresmall-minus { background-position: -64px -208px; }
-.ui-icon-squaresmall-close { background-position: -80px -208px; }
-.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
-.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
-.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
-.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
-
-
-/* Misc visuals
-----------------------------------*/
-
-/* Corner radius */
-.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; -khtml-border-top-left-radius: 3px; border-top-left-radius: 3px; }
-.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; -khtml-border-top-right-radius: 3px; border-top-right-radius: 3px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; -khtml-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; }
-.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; -khtml-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; }
-
-/* Overlays */
-.ui-widget-overlay { background: #e6b900 url(ui-bg_flat_0_e6b900_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
-.ui-widget-shadow { margin: 6px 0 0 6px; padding: 0px; background: #e69700 url(ui-bg_flat_0_e69700_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 3px; -khtml-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; }/*!
- * jQuery UI Resizable 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*!
- * jQuery UI Selectable 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*!
- * jQuery UI Accordion 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }
-/*!
- * jQuery UI Autocomplete 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }	
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu 1.8.23
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
-	list-style:none;
-	padding: 2px;
-	margin: 0;
-	display:block;
-	float: left;
-}
-.ui-menu .ui-menu {
-	margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
-	margin:0;
-	padding: 0;
-	zoom: 1;
-	float: left;
-	clear: left;
-	width: 100%;
-}
-.ui-menu .ui-menu-item a {
-	text-decoration:none;
-	display:block;
-	padding:.2em .4em;
-	line-height:1.5;
-	zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
-	font-weight: normal;
-	margin: -1px;
-}
-/*!
- * jQuery UI Button 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; } 
-button.ui-button-icons-only { width: 3.7em; } 
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4;  }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*!
- * jQuery UI Dialog 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative;  }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } 
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*!
- * jQuery UI Slider 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*!
- * jQuery UI Tabs 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*!
- * jQuery UI Datepicker 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month, 
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
-    position: absolute; /*must have*/
-    z-index: -1; /*must have*/
-    filter: mask(); /*must have*/
-    top: -4px; /*must have*/
-    left: -4px; /*must have*/
-    width: 200px; /*must have*/
-    height: 200px; /*must have*/
-}/*!
- * jQuery UI Progressbar 1.8.23
- *
- * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file


[17/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
new file mode 100644
index 0000000..69c3622
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE.txt" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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 the profiles that can apply to a workflow.
+ * 
+ * @author Donal K. Fellows
+ */
+@XmlRootElement(name = "profiles")
+@XmlType(name = "ProfileList")
+public class ProfileList {
+	public List<ProfileList.Info> profile = new ArrayList<ProfileList.Info>();
+
+	/**
+	 * Description of a single workflow profile.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "profile")
+	@XmlType(name = "Profile")
+	public static class Info {
+		@XmlValue
+		public String name;
+		/**
+		 * Whether this is the main profile.
+		 */
+		@XmlAttribute(name = "isMain")
+		public Boolean main;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
new file mode 100644
index 0000000..8079b1c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+/**
+ * The roles defined in this webapp.
+ * 
+ * @author Donal Fellows
+ */
+public interface Roles {
+	/** The role of a normal user. */
+	static final String USER = "ROLE_tavernauser";
+	/**
+	 * The role of an administrator. Administrators <i>should</i> have the
+	 * normal user role as well.
+	 */
+	static final String ADMIN = "ROLE_tavernasuperuser";
+	/**
+	 * The role of a workflow accessing itself. Do not give users this role.
+	 */
+	static final String SELF = "ROLE_tavernaworkflow";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
new file mode 100644
index 0000000..3486bf7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.VersionedElement.VERSION;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+/**
+ * A reference to a single workflow run, described using JAXB.
+ * 
+ * @author Donal Fellows
+ * @see org.taverna.server.master.interfaces.TavernaRun TavernaRun
+ */
+@XmlRootElement
+@XmlType(name = "TavernaRun")
+@XmlSeeAlso( { Workflow.class, DirEntryReference.class })
+public class RunReference {
+	/**
+	 * Where to get information about the run. For REST.
+	 */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	/** What version of server produced this element? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverVersion;
+	/**
+	 * The name of the run. For SOAP.
+	 */
+	@XmlValue
+	public String name;
+
+	/**
+	 * Make a blank run reference.
+	 */
+	public RunReference() {
+	}
+
+	/**
+	 * Make a reference to the given workflow run.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param ub
+	 *            A factory for URIs, or <tt>null</tt> if none is to be made.
+	 */
+	public RunReference(String name, UriBuilder ub) {
+		this.serverVersion = VERSION;
+		this.name = name;
+		if (ub != null)
+			this.link = ub.build(name);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
new file mode 100644
index 0000000..8e360dc
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Status.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * States of a workflow run. They are {@link #Initialized Initialized},
+ * {@link #Operating Operating}, {@link #Stopped Stopped}, and {@link #Finished
+ * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the
+ * workflow run does not exist (and hence can't have its state queried or set)
+ * in that case.
+ * 
+ * @author Donal Fellows
+ */
+@XmlEnum
+@XmlType(name = "Status")
+public enum Status {
+	/**
+	 * The workflow run has been created, but is not yet running. The run will
+	 * need to be manually moved to {@link #Operating Operating} when ready.
+	 */
+	Initialized,
+	/**
+	 * The workflow run is going, reading input, generating output, etc. Will
+	 * eventually either move automatically to {@link #Finished Finished} or can
+	 * be moved manually to {@link #Stopped Stopped} (where supported).
+	 */
+	Operating,
+	/**
+	 * The workflow run is paused, and will need to be moved back to
+	 * {@link #Operating Operating} manually.
+	 */
+	Stopped,
+	/**
+	 * The workflow run has ceased; data files will continue to exist until the
+	 * run is destroyed (which may be manual or automatic).
+	 */
+	Finished
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
new file mode 100644
index 0000000..6d77aa7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.io.Serializable;
+import java.security.cert.Certificate;
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A description of a trusted identity or identities. This description is
+ * characterised by a file visible to the workflow run that contains one or more
+ * certificates.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "TrustDescriptor")
+@XmlRootElement(name = "trustedIdentity")
+@SuppressWarnings("serial")
+public final class Trust implements Serializable {
+	/** The location of this descriptor in the REST world. */
+	@XmlAttribute(namespace = XLINK)
+	public String href;
+	/**
+	 * The location of this descriptor in the SOAP world. Must match corrected
+	 * with the {@link #href} field.
+	 */
+	@XmlTransient
+	public String id;
+	/**
+	 * The file containing the certificate(s). This is resolved with respect to
+	 * the workflow run working directory.
+	 */
+	@XmlElement
+	public String certificateFile;
+	/**
+	 * The type of certificate file. Defaults to <tt>X.509</tt> if unspecified.
+	 */
+	@XmlElement
+	public String fileType;
+	/**
+	 * The encoded serialized keystore containing the certificate(s).
+	 */
+	@XmlElement
+	public byte[] certificateBytes;
+	/**
+	 * The names of the server(s) identified by this trust.
+	 */
+	@XmlElement
+	public List<String> serverName;
+	/**
+	 * The collection of certificates loaded from the specified file. This is
+	 * always <tt>null</tt> before validation.
+	 */
+	public transient Collection<? extends Certificate> loadedCertificates;
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o == null || !(o instanceof Trust))
+			return false;
+		return id.equals(((Trust) o).id);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
new file mode 100644
index 0000000..d6d057c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriBuilderException;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.web.PortMapper;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A class that makes it simpler to work with an element with a {@link URI} in
+ * an <tt>href</tt> attribute. Done with JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Location")
+public class Uri {
+	static Log log = getLog("Taverna.Server.UriRewriter");
+	private static final String SECURE_SCHEME = "https";
+	/**
+	 * This type is characterised by an attribute that is the reference to some
+	 * other element.
+	 */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI ref;
+
+	/** Make a reference that points nowhere. */
+	public Uri() {
+	}
+
+	/**
+	 * Make a reference to the given location.
+	 * 
+	 * @param ref
+	 *            Where to point to.
+	 */
+	public Uri(@Nonnull URI ref) {
+		this.ref = secure(ref);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ub
+	 *            The configured factory.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriBuilder ub, String... strings) {
+		ref = secure(ub).build((Object[]) strings);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ui
+	 *            The factory factory.
+	 * @param path
+	 *            The path to configure the factory with.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriInfo ui, @Nonnull String path, String... strings) {
+		this(ui, true, path, strings);
+	}
+
+	/**
+	 * Make a reference from the factory with the given parameters.
+	 * 
+	 * @param ui
+	 *            The factory factory.
+	 * @param secure
+	 *            Whether the URI should be required to use HTTPS.
+	 * @param path
+	 *            The path to configure the factory with.
+	 * @param strings
+	 *            The parameters to the factory.
+	 */
+	public Uri(@Nonnull UriInfo ui, boolean secure, @Nonnull String path,
+			String... strings) {
+		UriBuilder ub = ui.getAbsolutePathBuilder();
+		if (secure) {
+			ub = secure(ub);
+		}
+		ref = ub.path(path).build((Object[]) strings);
+	}
+
+	public static UriBuilder secure(UriBuilder ub) {
+		return Rewriter.getInstance().getSecuredUriBuilder(ub);
+	}
+
+	public static UriBuilder secure(UriInfo ui) {
+		return secure(ui.getAbsolutePathBuilder());
+	}
+
+	public static URI secure(URI uri) {
+		URI newURI = secure(fromUri(uri)).build();
+		if (log.isDebugEnabled())
+			log.debug("rewrote " + uri + " to " + newURI);
+		return newURI;
+	}
+
+	public static URI secure(URI base, String uri) {
+		URI newURI = secure(fromUri(base.resolve(uri))).build();
+		if (log.isDebugEnabled())
+			log.debug("rewrote " + uri + " to " + newURI);
+		return newURI;
+	}
+
+	/**
+	 * A bean that allows configuration of how to rewrite generated URIs to be
+	 * secure.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class Rewriter {
+		private static Rewriter instance;
+		private PortMapper portMapper;
+		private boolean suppress;
+		private String rewriteRE = "://[^/]+/[^/]+";
+		private String rewriteTarget;
+
+		static Rewriter getInstance() {
+			if (instance == null)
+				new Rewriter();
+			return instance;
+		}
+
+		@Autowired
+		public void setPortMapper(PortMapper portMapper) {
+			this.portMapper = portMapper;
+		}
+
+		/**
+		 * Whether to suppress rewriting of URIs to be secure.
+		 * 
+		 * @param suppressSecurity
+		 *            True if no rewriting should be done.
+		 */
+		public void setSuppressSecurity(boolean suppressSecurity) {
+			suppress = suppressSecurity;
+		}
+
+		public void setRewriteRegexp(String rewriteRegexp) {
+			this.rewriteRE = rewriteRegexp;
+		}
+
+		/**
+		 * What to rewrite the host, port and web-app name to be.
+		 * 
+		 * @param rewriteTarget
+		 *            What to rewrite to, or "<tt>NONE</tt>" for no rewrite.
+		 */
+		public void setRewriteTarget(String rewriteTarget) {
+			if (rewriteTarget.isEmpty())
+				this.rewriteTarget = null;
+			else if (rewriteTarget.equals("NONE"))
+				this.rewriteTarget = null;
+			else if (rewriteTarget.startsWith("${"))
+				this.rewriteTarget = null;
+			else
+				this.rewriteTarget = "://" + rewriteTarget;
+		}
+
+		private Integer lookupHttpsPort(URI uri) {
+			if (portMapper != null)
+				return portMapper.lookupHttpsPort(uri.getPort());
+			return null;
+		}
+
+		public Rewriter() {
+			instance = this;
+		}
+
+		@PreDestroy
+		public void done() {
+			instance = null;
+			Uri.log = null;
+		}
+
+		@Nonnull
+		URI rewrite(@Nonnull String url) {
+			if (rewriteTarget != null)
+				url = url.replaceFirst(rewriteRE, rewriteTarget);
+			return URI.create(url);
+		}
+
+		@Nonnull
+		public UriBuilder getSecuredUriBuilder(@Nonnull UriBuilder uribuilder) {
+			if (suppress)
+				return uribuilder.clone();
+			UriBuilder ub = new RewritingUriBuilder(uribuilder);
+			Integer secPort = null;
+			try {
+				secPort = lookupHttpsPort(ub.build());
+			} catch (Exception e) {
+				/*
+				 * Do not log this; we know why it happens and don't actually
+				 * care to do anything about it. All it does is fill up the log
+				 * with pointless scariness!
+				 */
+
+				// log.debug("failed to extract current URI port", e);
+			}
+			if (secPort == null || secPort.intValue() == -1)
+				return ub.scheme(SECURE_SCHEME);
+			return ub.scheme(SECURE_SCHEME).port(secPort);
+		}
+
+		/**
+		 * {@link UriBuilder} that applies a rewrite rule to the URIs produced
+		 * by the wrapped builder.
+		 * 
+		 * @author Donal Fellows
+		 */
+		class RewritingUriBuilder extends UriBuilder {
+			private UriBuilder wrapped;
+
+			RewritingUriBuilder(UriBuilder builder) {
+				wrapped = builder.clone();
+			}
+
+			private URI rewrite(URI uri) {
+				return Rewriter.this.rewrite(uri.toString());
+			}
+
+			@Override
+			public UriBuilder clone() {
+				return new RewritingUriBuilder(wrapped);
+			}
+
+			@Override
+			public URI buildFromMap(Map<String, ?> values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromMap(values));
+			}
+
+			@Override
+			public URI buildFromEncodedMap(Map<String, ? extends Object> values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromEncodedMap(values));
+			}
+
+			@Override
+			public URI build(Object... values) throws IllegalArgumentException,
+					UriBuilderException {
+				return rewrite(wrapped.build(values));
+			}
+
+			@Override
+			public URI build(Object[] values, boolean encodeSlashInPath)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.build(values, encodeSlashInPath));
+			}
+
+			@Override
+			public URI buildFromEncoded(Object... values)
+					throws IllegalArgumentException, UriBuilderException {
+				return rewrite(wrapped.buildFromEncoded(values));
+			}
+
+			@Override
+			public URI buildFromMap(Map<String, ?> values,
+					boolean encodeSlashInPath) throws IllegalArgumentException,
+					UriBuilderException {
+				return rewrite(wrapped.buildFromEncoded(values,
+						encodeSlashInPath));
+			}
+
+			@Override
+			public UriBuilder uri(URI uri) throws IllegalArgumentException {
+				wrapped.uri(uri);
+				return this;
+			}
+
+			@Override
+			public UriBuilder uri(String uriTemplate)
+					throws IllegalArgumentException {
+				wrapped.uri(uriTemplate);
+				return this;
+			}
+
+			@Override
+			public String toTemplate() {
+				return wrapped.toTemplate();
+			}
+
+			@Override
+			public UriBuilder scheme(String scheme)
+					throws IllegalArgumentException {
+				wrapped.scheme(scheme);
+				return this;
+			}
+
+			@Override
+			public UriBuilder schemeSpecificPart(String ssp)
+					throws IllegalArgumentException {
+				wrapped.schemeSpecificPart(ssp);
+				return this;
+			}
+
+			@Override
+			public UriBuilder userInfo(String ui) {
+				wrapped.userInfo(ui);
+				return this;
+			}
+
+			@Override
+			public UriBuilder host(String host) throws IllegalArgumentException {
+				wrapped.host(host);
+				return this;
+			}
+
+			@Override
+			public UriBuilder port(int port) throws IllegalArgumentException {
+				wrapped.port(port);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replacePath(String path) {
+				wrapped.replacePath(path);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(String path) throws IllegalArgumentException {
+				wrapped.path(path);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(
+					@java.lang.SuppressWarnings("rawtypes") Class resource)
+					throws IllegalArgumentException {
+				wrapped.path(resource);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(
+					@java.lang.SuppressWarnings("rawtypes") Class resource,
+					String method) throws IllegalArgumentException {
+				wrapped.path(resource, method);
+				return this;
+			}
+
+			@Override
+			public UriBuilder path(Method method)
+					throws IllegalArgumentException {
+				wrapped.path(method);
+				return this;
+			}
+
+			@Override
+			public UriBuilder segment(String... segments)
+					throws IllegalArgumentException {
+				wrapped.segment(segments);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceMatrix(String matrix)
+					throws IllegalArgumentException {
+				wrapped.replaceMatrix(matrix);
+				return this;
+			}
+
+			@Override
+			public UriBuilder matrixParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.matrixParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceMatrixParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.replaceMatrixParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceQuery(String query)
+					throws IllegalArgumentException {
+				wrapped.replaceQuery(query);
+				return this;
+			}
+
+			@Override
+			public UriBuilder queryParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.queryParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder replaceQueryParam(String name, Object... values)
+					throws IllegalArgumentException {
+				wrapped.replaceQueryParam(name, values);
+				return this;
+			}
+
+			@Override
+			public UriBuilder fragment(String fragment) {
+				wrapped.fragment(fragment);
+				return this;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
new file mode 100644
index 0000000..6eddf2d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * The type of an element that declares the version of the server that produced
+ * it.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "VersionedElement", namespace = SERVER)
+public abstract class VersionedElement {
+	/** What version of server produced this element? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverVersion;
+	/** What revision of server produced this element? Derived from SCM commit. */
+	@XmlAttribute(namespace = SERVER)
+	public String serverRevision;
+	/** When was the server built? */
+	@XmlAttribute(namespace = SERVER)
+	public String serverBuildTimestamp;
+	public static final String VERSION, REVISION, TIMESTAMP;
+	static {
+		Log log = getLog("Taverna.Server.Webapp");
+		Properties p = new Properties();
+		try {
+			try (InputStream is = VersionedElement.class
+					.getResourceAsStream("/version.properties")) {
+				p.load(is);
+			}
+		} catch (IOException e) {
+			log.warn("failed to read /version.properties", e);
+		}
+		VERSION = p.getProperty("tavernaserver.version", "unknownVersion");
+		REVISION = String.format("%s (tag: %s)",
+				p.getProperty("tavernaserver.branch", "unknownRevision"),
+				p.getProperty("tavernaserver.revision.describe", "unknownTag"));
+		TIMESTAMP = p
+				.getProperty("tavernaserver.timestamp", "unknownTimestamp");
+	}
+
+	public VersionedElement() {
+	}
+
+	protected VersionedElement(boolean ignored) {
+		serverVersion = VERSION;
+		serverRevision = REVISION;
+		serverBuildTimestamp = TIMESTAMP;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
new file mode 100644
index 0000000..ba6a68c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static javax.xml.bind.Marshaller.JAXB_ENCODING;
+import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
+import static javax.xml.bind.annotation.XmlAccessType.NONE;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URL;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.taverna.server.master.rest.handler.Scufl2DocumentHandler;
+import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import uk.org.taverna.scufl2.api.common.NamedSet;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.io.ReaderException;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+import uk.org.taverna.scufl2.api.io.WriterException;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Encapsulation of a T2flow or Scufl2 document.
+ * 
+ * @author Donal K. Fellows
+ */
+@XmlRootElement(name = "workflow")
+@XmlType(name = "Workflow")
+@XmlAccessorType(NONE)
+public class Workflow implements Serializable, Externalizable {
+	/** Literal document, if present. */
+	@XmlAnyElement(lax = true)
+	private Element content;
+	/** SCUFL2 bundle, if present. */
+	@XmlTransient
+	private WorkflowBundle bundle;
+	/** Which came first, the bundle or the t2flow document. */
+	@XmlTransient
+	private boolean isBundleFirst;
+
+	private static Marshaller marshaller;
+	private static Unmarshaller unmarshaller;
+	private final static String ENCODING = "UTF-8";
+	private final static WorkflowBundleIO io;
+	static {
+		try {
+			JAXBContext context = JAXBContext.newInstance(Workflow.class);
+			marshaller = context.createMarshaller();
+			unmarshaller = context.createUnmarshaller();
+			marshaller.setProperty(JAXB_ENCODING, ENCODING);
+			marshaller.setProperty(JAXB_FORMATTED_OUTPUT, false);
+		} catch (JAXBException e) {
+			getLog("Taverna.Server.Webapp").fatal(
+					"failed to build JAXB context for working with "
+							+ Workflow.class, e);
+		}
+		io = new WorkflowBundleIO();
+	}
+
+	public enum ContentType {
+		T2FLOW(T2FlowDocumentHandler.T2FLOW), SCUFL2(
+				Scufl2DocumentHandler.SCUFL2);
+		private String type;
+
+		ContentType(String type) {
+			this.type = type;
+		}
+
+		public String getContentType() {
+			return type;
+		}
+	}
+
+	public Workflow() {
+	}
+
+	public Workflow(Element element) {
+		this.content = element;
+		this.isBundleFirst = false;
+	}
+
+	public Workflow(WorkflowBundle bundle) {
+		this.bundle = bundle;
+		this.isBundleFirst = true;
+	}
+
+	public Workflow(URL url) throws ReaderException, IOException {
+		this(io.readBundle(url, null));
+	}
+
+	/**
+	 * What content type would this workflow "prefer" to be?
+	 */
+	public ContentType getPreferredContentType() {
+		if (isBundleFirst)
+			return ContentType.SCUFL2;
+		else
+			return ContentType.T2FLOW;
+	}
+
+	/**
+	 * Retrieves the workflow as a SCUFL2 document, converting it if necessary.
+	 * 
+	 * @return The SCUFL2 document.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	public WorkflowBundle getScufl2Workflow() throws IOException {
+		try {
+			if (bundle == null)
+				bundle = io.readBundle(new ByteArrayInputStream(getAsT2Flow()),
+						T2FLOW);
+			return bundle;
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException("problem when converting to SCUFL2", e);
+		}
+	}
+
+	/**
+	 * Get the bytes of the serialized SCUFL2 workflow.
+	 * 
+	 * @return Array of bytes.
+	 * @throws IOException
+	 *             If serialization fails.
+	 * @throws WriterException
+	 *             If conversion fails.
+	 */
+	public byte[] getScufl2Bytes() throws IOException, WriterException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		io.writeBundle(getScufl2Workflow(), baos, SCUFL2);
+		return baos.toByteArray();
+	}
+
+	/**
+	 * Retrieves the workflow as a T2Flow document, converting it if necessary.
+	 * 
+	 * @return The T2Flow document.
+	 * @throws IOException
+	 *             If anything goes wrong.
+	 */
+	public Element getT2flowWorkflow() throws IOException {
+		try {
+			if (content != null)
+				return content;
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			io.writeBundle(bundle, baos, T2FLOW);
+			Document doc;
+			try {
+				DocumentBuilderFactory dbf = DocumentBuilderFactory
+						.newInstance();
+				dbf.setNamespaceAware(true);
+				doc = dbf.newDocumentBuilder().parse(
+						new ByteArrayInputStream(baos.toByteArray()));
+			} catch (SAXException e) {
+				throw new IOException("failed to convert to DOM tree", e);
+			}
+			Element e = doc.getDocumentElement();
+			if (e.getNamespaceURI().equals(T2FLOW_NS)
+					&& e.getNodeName().equals(T2FLOW_ROOTNAME))
+				return content = e;
+			throw new IOException(
+					"unexpected element when converting to T2Flow: {"
+							+ e.getNamespaceURI() + "}" + e.getNodeName());
+		} catch (IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new IOException("problem when converting to SCUFL2", e);
+		}
+	}
+
+	/**
+	 * @return The name of the main workflow profile, or <tt>null</tt> if there
+	 *         is none.
+	 */
+	public String getMainProfileName() {
+		try {
+			return getScufl2Workflow().getMainProfile().getName();
+		} catch (IOException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * @return The set of profiles supported over this workflow.
+	 */
+	public NamedSet<Profile> getProfiles() {
+		try {
+			return getScufl2Workflow().getProfiles();
+		} catch (IOException e) {
+			return new NamedSet<Profile>();
+		}
+	}
+
+	/**
+	 * Convert from marshalled form.
+	 * 
+	 * @throws JAXBException
+	 *             If the conversion fails.
+	 */
+	public static Workflow unmarshal(String representation)
+			throws JAXBException {
+		StringReader sr = new StringReader(representation);
+		return (Workflow) unmarshaller.unmarshal(sr);
+	}
+
+	/**
+	 * Convert to marshalled form.
+	 */
+	public String marshal() throws JAXBException {
+		StringWriter sw = new StringWriter();
+		marshaller.marshal(this, sw);
+		return sw.toString();
+	}
+
+	@Override
+	public void readExternal(ObjectInput in) throws IOException,
+			ClassNotFoundException {
+		try {
+			ByteArrayInputStream bytes = readbytes(in);
+			if (bytes != null)
+				try (Reader r = new InputStreamReader(bytes, ENCODING)) {
+					content = ((Workflow) unmarshaller.unmarshal(r)).content;
+				}
+			bytes = readbytes(in);
+			if (bytes != null)
+				bundle = io.readBundle(bytes, SCUFL2);
+			isBundleFirst = in.readBoolean();
+			return;
+		} catch (JAXBException e) {
+			throw new IOException("failed to unmarshal", e);
+		} catch (ClassCastException e) {
+			throw new IOException("bizarre result of unmarshalling", e);
+		} catch (ReaderException e) {
+			throw new IOException("failed to unmarshal", e);
+		}
+	}
+
+	private byte[] getAsT2Flow() throws IOException, JAXBException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		OutputStreamWriter w = new OutputStreamWriter(baos, ENCODING);
+		marshaller.marshal(this, w);
+		w.close();
+		return baos.toByteArray();
+	}
+
+	private byte[] getAsScufl2() throws IOException, WriterException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		io.writeBundle(bundle, baos, SCUFL2);
+		baos.close();
+		return baos.toByteArray();
+	}
+
+	@Override
+	public void writeExternal(ObjectOutput out) throws IOException {
+		try {
+			writebytes(out, (content != null) ? getAsT2Flow() : null);
+		} catch (JAXBException e) {
+			throw new IOException("failed to marshal t2flow", e);
+		}
+		try {
+			writebytes(out, (bundle != null) ? getAsScufl2() : null);
+		} catch (WriterException e) {
+			throw new IOException("failed to marshal scufl2", e);
+		}
+		out.writeBoolean(isBundleFirst);
+	}
+
+	private ByteArrayInputStream readbytes(ObjectInput in) throws IOException {
+		int len = in.readInt();
+		if (len > 0) {
+			byte[] bytes = new byte[len];
+			in.readFully(bytes);
+			return new ByteArrayInputStream(bytes);
+		}
+		return null;
+	}
+
+	private void writebytes(ObjectOutput out, byte[] data) throws IOException {
+		out.writeInt(data == null ? 0 : data.length);
+		if (data != null && data.length > 0)
+			out.write(data);
+	}
+
+	/**
+	 * Make up for the lack of an integrated XPath engine.
+	 * 
+	 * @param name
+	 *            The element names to look up from the root of the contained
+	 *            document.
+	 * @return The looked up element, or <tt>null</tt> if it doesn't exist.
+	 */
+	private Element getEl(String... name) {
+		Element el = content;
+		boolean skip = true;
+		for (String n : name) {
+			if (skip) {
+				skip = false;
+				continue;
+			}
+			if (el == null)
+				return null;
+			NodeList nl = el.getElementsByTagNameNS(T2FLOW_NS, n);
+			if (nl.getLength() == 0)
+				return null;
+			Node node = nl.item(0);
+			if (node instanceof Element)
+				el = (Element) node;
+			else
+				return null;
+		}
+		return el;
+	}
+
+	/**
+	 * @return The content of the embedded
+	 *         <tt>&lt;workflow&gt;&lt;dataflow&gt;&lt;name&gt;</tt> element.
+	 */
+	@XmlTransient
+	public String getName() {
+		return getEl("workflow", "dataflow", "name").getTextContent();
+	}
+
+	/**
+	 * @return The embedded <tt>&lt;workflow&gt;</tt> element.
+	 */
+	@XmlTransient
+	public Element getWorkflowRoot() {
+		return getEl("workflow");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
new file mode 100644
index 0000000..fd040de
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the common XML elements used throughout Taverna Server's various interfaces.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.common;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
new file mode 100644
index 0000000..e9c58a9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common.version;
+
+import static org.taverna.server.master.common.version.Constants.PATCH;
+import static org.taverna.server.master.common.version.Constants.VERSION;
+
+/**
+ * Common location for describing the version of the server.
+ * 
+ * @author Donal Fellows
+ */
+public interface Version {
+	public static final String JAVA = VERSION + Constants.releaseChar + PATCH;
+	public static final String HTML = VERSION + Constants.releaseHEnt + PATCH;
+	public static final String XML = VERSION + Constants.releaseXEnt + PATCH;
+}
+
+/**
+ * The pieces of a version string.
+ * 
+ * @author Donal Fellows
+ */
+interface Constants {
+	static final String MAJOR = "2";
+	static final String MINOR = "5";
+	static final String PATCH = "4";
+
+	static final char alphaChar = '\u03b1';
+	static final char betaChar = '\u03b2';
+	static final char releaseChar = '.';
+	static final String alphaHEnt = "&alpha;";
+	static final String betaHEnt = "&beta;";
+	static final String releaseHEnt = ".";
+	static final String alphaXEnt = "&#x03b1;";
+	static final String betaXEnt = "&#x03b2;";
+	static final String releaseXEnt = ".";
+
+	static final String VERSION = MAJOR + "." + MINOR;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
new file mode 100644
index 0000000..c2a2bc9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.defaults;
+
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.localworker.LocalWorkerState;
+
+/**
+ * This defines a collection of default values, collecting them from various
+ * parts of the server.
+ * 
+ * @author Donal Fellows
+ */
+public interface Default {
+	/** The default value of the <tt>prefix</tt> property. */
+	static final String AUTHORITY_PREFIX = "LOCALUSER_";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that this class will fork off.
+	 */
+	static final String SERVER_WORKER_IMPLEMENTATION_JAR = "util/server.worker.jar";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that manages secure forking.
+	 */
+	static final String SECURE_FORK_IMPLEMENTATION_JAR = "util/secure.fork.jar";
+
+	/**
+	 * The name of the resource that is the implementation of the subprocess
+	 * that acts as the RMI registry.
+	 */
+	static final String REGISTRY_JAR = "util/rmi.daemon.jar";
+
+	/** Initial lifetime of runs, in minutes. */
+	static final int RUN_LIFE_MINUTES = 20;
+
+	/**
+	 * Maximum number of runs to exist at once. Note that this includes when
+	 * they are just existing for the purposes of file transfer (
+	 * {@link Status#Initialized}/{@link Status#Finished} states).
+	 */
+	static final int RUN_COUNT_MAX = 5;
+
+	/**
+	 * Prefix to use for RMI names.
+	 */
+	static final String RMI_PREFIX = "ForkRunFactory.";
+
+	/** Default value for {@link LocalWorkerState#passwordFile}. */
+	static final String PASSWORD_FILE = null;
+
+	/**
+	 * The extra arguments to pass to the subprocess.
+	 */
+	static final String[] EXTRA_ARGUMENTS = new String[0];
+
+	/**
+	 * How long to wait for subprocess startup, in seconds.
+	 */
+	static final int SUBPROCESS_START_WAIT = 40;
+
+	/**
+	 * Polling interval to use during startup, in milliseconds.
+	 */
+	static final int SUBPROCESS_START_POLL_SLEEP = 1000;
+
+	/**
+	 * Maximum number of {@link Status#Operating} runs at any time.
+	 */
+	static final int RUN_OPERATING_LIMIT = 10;
+
+	/**
+	 * What fields of a certificate we look at when understanding who it is
+	 * talking about, in the order that we look.
+	 */
+	static final String[] CERTIFICATE_FIELD_NAMES = { "CN", "COMMONNAME",
+			"COMMON NAME", "COMMON_NAME", "OU", "ORGANIZATIONALUNITNAME",
+			"ORGANIZATIONAL UNIT NAME", "O", "ORGANIZATIONNAME",
+			"ORGANIZATION NAME" };
+
+	/** The type of certificates that are processed if we don't say otherwise. */
+	static final String CERTIFICATE_TYPE = "X.509";
+
+	/** Max size of credential file, in kiB. */
+	static final int CREDENTIAL_FILE_SIZE_LIMIT = 20;
+
+	/**
+	 * The notification message format to use if none is configured.
+	 */
+	public static final String NOTIFY_MESSAGE_FORMAT = "Your job with ID={0} has finished with exit code {1,number,integer}.";
+
+	/** The address of the SMS gateway service used. */
+	public static final String SMS_GATEWAY_URL = "https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
new file mode 100644
index 0000000..239b260
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains information about the various default values supported by the server.
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.defaults;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
new file mode 100644
index 0000000..0b6247e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates that the port name was not recognized.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "BadInputPortNameFault")
+@SuppressWarnings("serial")
+public class BadInputPortNameException extends Exception {
+	public BadInputPortNameException(String msg) {
+		super(msg);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
new file mode 100644
index 0000000..303b19b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates a bad property value.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "BadPropertyValueFault")
+public class BadPropertyValueException extends NoListenerException {
+	private static final long serialVersionUID = -8459491388504556875L;
+
+	public BadPropertyValueException(String msg) {
+		super(msg);
+	}
+
+	public BadPropertyValueException(String msg, Throwable e) {
+		super(msg, e);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
new file mode 100644
index 0000000..4b843e2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the state change requested for a
+ * run is impossible.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoUpdateFault")
+public class BadStateChangeException extends NoUpdateException {
+	private static final long serialVersionUID = -4490826388447601775L;
+
+	public BadStateChangeException() {
+		super("cannot do that state change");
+	}
+
+	public BadStateChangeException(Throwable t) {
+		super("cannot do that state change", t);
+	}
+
+	public BadStateChangeException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+	public BadStateChangeException(String message) {
+		super(message);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
new file mode 100644
index 0000000..0b6cf07
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import java.rmi.RemoteException;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * An exception that happened when the underlying filesystem was accessed.
+ * @author Donal Fellows
+ */
+@WebFault(name = "FilesystemAccessFault")
+public class FilesystemAccessException extends Exception {
+	private static final long serialVersionUID = 8715937300989820318L;
+
+	public FilesystemAccessException(String msg) {
+		super(msg);
+	}
+
+	public FilesystemAccessException(String string, Throwable cause) {
+		super(string, getRealCause(cause));
+	}
+
+	private static Throwable getRealCause(Throwable t) {
+		if (t instanceof RemoteException) {
+			RemoteException remote = (RemoteException) t;
+			if (remote.detail != null)
+				return remote.detail;
+		}
+		if (t.getCause() != null)
+			return t.getCause();
+		return t;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
new file mode 100644
index 0000000..11d47c7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Some sort of exception that occurred which we can't map any other way. This
+ * is generally indicative of a problem server-side.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "GeneralFailureFault", targetNamespace = SERVER_SOAP)
+@SuppressWarnings("serial")
+public class GeneralFailureException extends RuntimeException {
+	public GeneralFailureException(Throwable cause) {
+		super(cause.getMessage(), cause);
+	}
+
+	public GeneralFailureException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
new file mode 100644
index 0000000..67ba551
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+/**
+ * An exception that is thrown to indicate that a credential-descriptor or
+ * trust-descriptor supplied as part of a credential or trust management
+ * operation is invalid.
+ * 
+ * @author Donal Fellows
+ * 
+ */
+@SuppressWarnings("serial")
+public class InvalidCredentialException extends Exception {
+	private static final String MSG = "that credential is invalid";
+
+	public InvalidCredentialException() {
+		super(MSG);
+	}
+
+	public InvalidCredentialException(String reason) {
+		super(MSG + ": " + reason);
+	}
+
+	public InvalidCredentialException(String reason, Throwable cause) {
+		this(reason);
+		initCause(cause);
+	}
+
+	public InvalidCredentialException(Throwable cause) {
+		this(cause.getMessage(), cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
new file mode 100644
index 0000000..e2ddf4c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to
+ * create something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoCreateFault")
+public class NoCreateException extends NoUpdateException {
+	private static final long serialVersionUID = 270413810410167235L;
+
+	public NoCreateException() {
+		super("not permitted to create");
+	}
+
+	public NoCreateException(String string) {
+		super(string);
+	}
+
+	public NoCreateException(String string, Throwable e) {
+		super(string, e);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
new file mode 100644
index 0000000..7077fc4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+/**
+ * Exception that indicates the absence of an expected credential.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class NoCredentialException extends Exception {
+	public NoCredentialException() {
+		super("no such credential");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
new file mode 100644
index 0000000..d7b0d29
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to
+ * destroy something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoDestroyFault")
+public class NoDestroyException extends NoUpdateException {
+	private static final long serialVersionUID = 6207448533265237933L;
+
+	public NoDestroyException() {
+		super("not permitted to destroy");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
new file mode 100644
index 0000000..0d6ca63
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Indicates that the file or directory name was not recognized.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoDirectoryEntryFault")
+@SuppressWarnings("serial")
+public class NoDirectoryEntryException extends Exception {
+	public NoDirectoryEntryException(String msg) {
+		super(msg);
+	}
+	public NoDirectoryEntryException(String msg,Exception cause) {
+		super(msg, cause);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
new file mode 100644
index 0000000..f4b8e81
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception thrown to indicate that no listener by that name exists, or that
+ * some other problem with listeners has occurred.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoListenerFault")
+@XmlSeeAlso(BadPropertyValueException.class)
+public class NoListenerException extends Exception {
+	private static final long serialVersionUID = -2550897312787546547L;
+
+	public NoListenerException() {
+		super("no such listener");
+	}
+
+	public NoListenerException(String msg) {
+		super(msg);
+	}
+
+	public NoListenerException(String msg, Throwable t) {
+		super(msg, t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
new file mode 100644
index 0000000..c49d111
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the user is not permitted to update
+ * something.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NoUpdateFault")
+@XmlSeeAlso( { NoCreateException.class, NoDestroyException.class, BadStateChangeException.class })
+public class NoUpdateException extends Exception {
+	private static final long serialVersionUID = 4230987102653846379L;
+
+	public NoUpdateException() {
+		super("not permitted to update");
+	}
+
+	public NoUpdateException(String msg) {
+		super(msg);
+	}
+
+	public NoUpdateException(String string, Throwable e) {
+		super(string, e);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
new file mode 100644
index 0000000..6e1f792
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * An exception thrown when an operation is attempted which only the owner is
+ * permitted to do. Notably, permissions may <i>only</i> be manipulated by the
+ * owner.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "NotOwnerFault")
+@SuppressWarnings("serial")
+public class NotOwnerException extends Exception {
+	public NotOwnerException() {
+		super("not permitted; not the owner");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
new file mode 100644
index 0000000..dda371e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception that is thrown to indicate that the state change requested for a
+ * run is currently impossible due to excessive server load.
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "OverloadedFault")
+public class OverloadedException extends BadStateChangeException {
+	private static final long serialVersionUID = 490826388447601776L;
+
+	public OverloadedException() {
+		super("server too busy; try later please");
+	}
+
+	public OverloadedException(Throwable t) {
+		super("server too busy; try later please", t);
+	}
+
+	public OverloadedException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+	public OverloadedException(String message) {
+		super(message);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
new file mode 100644
index 0000000..4632d4a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.exceptions;
+
+import javax.xml.ws.WebFault;
+
+/**
+ * Exception thrown to indicate that the handle of the run is unknown (or
+ * unacceptable to the current user).
+ * 
+ * @author Donal Fellows
+ */
+@WebFault(name = "UnknownRunFault")
+public class UnknownRunException extends Exception {
+	private static final long serialVersionUID = -3028749401786242841L;
+
+	public UnknownRunException() {
+		super("unknown run UUID");
+	}
+
+	public UnknownRunException(Throwable t) {
+		super("implementation problems", t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
new file mode 100644
index 0000000..29ccacd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the exceptions/faults thrown by Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.exceptions;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
new file mode 100644
index 0000000..0015754
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.facade;
+
+import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE;
+import static javax.ws.rs.core.Response.ok;
+
+import java.io.IOException;
+import java.net.URL;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.utils.Contextualizer;
+
+/**
+ * This is a simple class that is used to serve up a file (with a simple
+ * substitution applied) as the root of the T2Server webapp.
+ * 
+ * @author Donal Fellows
+ */
+@Path("/")
+public class Facade {
+	private Log log = LogFactory.getLog("Taverna.Server.Utils");
+	private String welcome;
+	private Contextualizer contextualizer;
+
+	/**
+	 * Set what resource file to use as the template for the response.
+	 * 
+	 * @param file
+	 *            The file from which to load the data (presumed HTML) to serve
+	 *            up as the root content.
+	 * @throws IOException
+	 *             If the file doesn't exist.
+	 */
+	public void setFile(String file) throws IOException {
+		URL full = Facade.class.getResource(file);
+		log.info("setting " + full + " as source of root page");
+		this.welcome = IOUtils.toString(full);
+	}
+
+	@Required
+	public void setContextualizer(Contextualizer contextualizer) {
+		this.contextualizer = contextualizer;
+	}
+
+	/**
+	 * Serve up some HTML as the root of the service.
+	 * 
+	 * @param ui
+	 *            A reference to how we were accessed by the service.
+	 * @return The response, containing the HTML.
+	 */
+	@GET
+	@Path("{dummy:.*}")
+	@Produces("text/html")
+	public Response get(@Context UriInfo ui) {
+		return ok(contextualizer.contextualize(ui, welcome), TEXT_HTML_TYPE)
+				.build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
new file mode 100644
index 0000000..73c884f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Simple facade used at the top level of the Taverna Server in order to
+ * provide an entry splash page.
+ */
+package org.taverna.server.master.facade;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
new file mode 100644
index 0000000..954b6f1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.factories;
+
+/**
+ * Interface to run factories for the purpose of configuration.
+ * 
+ * @author Donal Fellows
+ */
+public interface ConfigurableRunFactory extends RunFactory {
+	/** Where is the registry? Getter */
+	String getRegistryHost();
+
+	/** Where is the registry? Setter */
+	void setRegistryHost(String host);
+
+	/** Where is the registry? Getter */
+	int getRegistryPort();
+
+	/** Where is the registry? Setter */
+	void setRegistryPort(int port);
+
+	/** How much can be done at once? Getter */
+	int getMaxRuns();
+
+	/** How much can be done at once? Setter */
+	void setMaxRuns(int maxRuns);
+
+	/** How long will things live? Getter */
+	int getDefaultLifetime();
+
+	/** How long will things live? Setter */
+	void setDefaultLifetime(int defaultLifetime);
+
+	/** How often do we probe for info? Getter */
+	int getSleepTime();
+
+	/** How often do we probe for info? Setter */
+	void setSleepTime(int sleepTime);
+
+	/** How long do we allow for actions? Getter */
+	int getWaitSeconds();
+
+	/** How long do we allow for actions? Setter */
+	void setWaitSeconds(int seconds);
+
+	/** How do we start the workflow engine? Getter */
+	String getExecuteWorkflowScript();
+
+	/** How do we start the workflow engine? Setter */
+	void setExecuteWorkflowScript(String executeWorkflowScript);
+
+	/** How do we start the file system access process? Getter */
+	String getServerWorkerJar();
+
+	/** How do we start the file system access process? Setter */
+	void setServerWorkerJar(String serverWorkerJar);
+
+	/**
+	 * How do we start the file system access process? Extra arguments to pass.
+	 * Getter
+	 */
+	String[] getExtraArguments();
+
+	/**
+	 * How do we start the file system access process? Extra arguments to pass.
+	 * Setter
+	 */
+	void setExtraArguments(String[] firstArguments);
+
+	/** Where is Java? Getter */
+	String getJavaBinary();
+
+	/** Where is Java? Setter */
+	void setJavaBinary(String javaBinary);
+
+	/** Where do we get passwords from? Getter */
+	String getPasswordFile();
+
+	/** Where do we get passwords from? Setter */
+	void setPasswordFile(String newValue);
+
+	/** How do we switch users? Getter */
+	String getServerForkerJar();
+
+	/** How do we switch users? Setter */
+	void setServerForkerJar(String newValue);
+
+	/** How many runs have there been? */
+	int getTotalRuns();
+
+	/** How long did the last subprocess startup take? */
+	int getLastStartupCheckCount();
+
+	/** What are the current runs? */
+	String[] getCurrentRunNames();
+
+	/** What is the RMI ID of the factory process? */
+	String getFactoryProcessName();
+
+	/** What was the last observed exit code? */
+	Integer getLastExitCode();
+
+	/** What factory process to use for a particular user? */
+	String[] getFactoryProcessMapping();
+
+	/** How many runs can be operating at once? Setter */
+	void setOperatingLimit(int operatingLimit);
+
+	/** How many runs can be operating at once? Getter */
+	int getOperatingLimit();
+
+	/**
+	 * How many runs are actually operating?
+	 * 
+	 * @throws Exception
+	 *             if anything goes wrong
+	 */
+	int getOperatingCount() throws Exception;
+
+	/** How do we start the RMI registry process? Getter */
+	String getRmiRegistryJar();
+
+	/** How do we start the RMI registry process? Setter */
+	void setRmiRegistryJar(String rmiRegistryJar);
+
+	boolean getGenerateProvenance();
+
+	void setGenerateProvenance(boolean generateProvenance);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
new file mode 100644
index 0000000..ecc13cd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.factories;
+
+import java.util.List;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * How to make event listeners of various types that are attached to a workflow
+ * instance.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenerFactory {
+	/**
+	 * Make an event listener.
+	 * 
+	 * @param run
+	 *            The workflow instance to attach the event listener to.
+	 * @param listenerType
+	 *            The type of event listener to create. Must be one of the
+	 *            strings returned by {@link #getSupportedListenerTypes()}.
+	 * @param configuration
+	 *            A configuration document to pass to the listener.
+	 * @return The event listener that was created.
+	 * @throws NoListenerException
+	 *             If the <b>listenerType</b> is unrecognized or the
+	 *             <b>configuration</b> is bad in some way.
+	 */
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException;
+
+	/**
+	 * What types of listener are supported? Note that we assume that the list
+	 * of types is the same for all users and all workflow instances.
+	 * 
+	 * @return A list of supported listener types.
+	 */
+	public List<String> getSupportedListenerTypes();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
new file mode 100644
index 0000000..eeacad7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.factories;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * How to construct a Taverna Server Workflow Run.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunFactory {
+	/**
+	 * Make a Taverna Server workflow run that is bound to a particular user
+	 * (the "creator") and able to run a particular workflow.
+	 * 
+	 * @param creator
+	 *            The user creating the workflow instance.
+	 * @param workflow
+	 *            The workflow to instantiate
+	 * @return An object representing the run.
+	 * @throws NoCreateException
+	 *             On failure.
+	 */
+	TavernaRun create(UsernamePrincipal creator, Workflow workflow)
+			throws NoCreateException;
+
+	/**
+	 * Check whether the factory is permitting runs to actually start operating.
+	 * 
+	 * @return Whether a run should start.
+	 */
+	boolean isAllowingRunsToStart();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
new file mode 100644
index 0000000..39b9ac6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * These interfaces define the principal way for the <i>factories</i> of
+ * worker classes to be invoked.
+ */
+package org.taverna.server.master.factories;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
new file mode 100644
index 0000000..63402ef
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Extracts the local user id from the set of Spring Security authorities
+ * granted to the current user. This is done by scanning the set of authorities
+ * to see if any of them start with the substring listed in the <tt>prefix</tt>
+ * property; the username is the rest of the authority string in that case.
+ * 
+ * @author Donal Fellows
+ */
+public class AuthorityDerivedIDMapper implements LocalIdentityMapper {
+	private String prefix = AUTHORITY_PREFIX;
+
+	public String getPrefix() {
+		return prefix;
+	}
+
+	public void setPrefix(String prefix) {
+		this.prefix = prefix;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		Authentication auth = SecurityContextHolder.getContext()
+				.getAuthentication();
+		if (auth == null || !auth.isAuthenticated())
+			return null;
+		for (GrantedAuthority authority : auth.getAuthorities()) {
+			String token = authority.getAuthority();
+			if (token == null)
+				continue;
+			if (token.startsWith(prefix))
+				return token.substring(prefix.length());
+		}
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
new file mode 100644
index 0000000..b5fcd5a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * An identity mapper that composes the results from other mappers, using the
+ * identity mappers in order until one can provide a non-<tt>null</tt> answer.
+ * 
+ * @author Donal Fellows.
+ */
+public class CompositeIDMapper implements LocalIdentityMapper,
+		ApplicationContextAware {
+	private Log log = getLog("Taverna.Server.IdentityMapper");
+	private List<LocalIdentityMapper> mappers;
+	private ApplicationContext context;
+
+	/**
+	 * @param mappers
+	 *            The list of mappers to delegate to. Order is significant.
+	 */
+	public void setIdentityMappers(List<LocalIdentityMapper> mappers) {
+		this.mappers = mappers;
+	}
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext)
+			throws BeansException {
+		context = applicationContext;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		if (mappers == null)
+			return null;
+		for (LocalIdentityMapper m : mappers) {
+			String u = m.getUsernameForPrincipal(user);
+			if (u == null)
+				continue;
+			for (Entry<String, ? extends LocalIdentityMapper> entry : context
+					.getBeansOfType(m.getClass()).entrySet())
+				if (m == entry.getValue()) {
+					log.info("used " + entry.getKey() + " LIM to map " + user
+							+ " to " + u);
+					break;
+				}
+			return u;
+		}
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
new file mode 100644
index 0000000..e81f926
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A trivial principal to user mapper that always uses the same ID.
+ * @author Donal Fellows
+ */
+public class ConstantIDMapper implements LocalIdentityMapper {
+	private String id;
+
+	/**
+	 * Sets what local user ID all users should be mapped to.
+	 * 
+	 * @param id
+	 *            The local user ID.
+	 */
+	public void setConstantId(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		return id;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
new file mode 100644
index 0000000..42a3874
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.identity;
+
+import static java.util.regex.Pattern.compile;
+
+import java.security.Principal;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A trivial identity mapper that just uses the name out of the
+ * {@link Principal}, or uses a regular expression to extract it from the string
+ * representation of the principal.
+ * 
+ * @author Donal Fellows
+ */
+public class NameIDMapper implements LocalIdentityMapper {
+	private Pattern pat;
+
+	/**
+	 * @param regexp
+	 *            The regular expression to use. The first capturing group
+	 *            within the RE will be the result of the extraction.
+	 * @throws PatternSyntaxException
+	 *             If the pattern is invalid.
+	 */
+	public void setRegexp(String regexp) throws PatternSyntaxException {
+		pat = compile(regexp);
+	}
+
+	@Override
+	public String getUsernameForPrincipal(UsernamePrincipal user) {
+		if (pat != null) {
+			Matcher m = pat.matcher(user.toString());
+			if (m.find() && m.groupCount() > 0) {
+				return m.group(1);
+			}
+			return null;
+		}
+		return user.getName();
+	}
+}


[42/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java b/server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
deleted file mode 100644
index 184c7b5..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
+++ /dev/null
@@ -1,1100 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.admin;
-
-import static org.taverna.server.master.admin.Paths.ALLOW_NEW;
-import static org.taverna.server.master.admin.Paths.ARGS;
-import static org.taverna.server.master.admin.Paths.EXEC_WF;
-import static org.taverna.server.master.admin.Paths.EXITCODE;
-import static org.taverna.server.master.admin.Paths.FACTORIES;
-import static org.taverna.server.master.admin.Paths.GEN_PROV;
-import static org.taverna.server.master.admin.Paths.INVOKES;
-import static org.taverna.server.master.admin.Paths.JAR_FORKER;
-import static org.taverna.server.master.admin.Paths.JAR_WORKER;
-import static org.taverna.server.master.admin.Paths.JAVA;
-import static org.taverna.server.master.admin.Paths.LIFE;
-import static org.taverna.server.master.admin.Paths.LOG_EXN;
-import static org.taverna.server.master.admin.Paths.LOG_WFS;
-import static org.taverna.server.master.admin.Paths.OPERATING;
-import static org.taverna.server.master.admin.Paths.OP_LIMIT;
-import static org.taverna.server.master.admin.Paths.PASSFILE;
-import static org.taverna.server.master.admin.Paths.PERM_WF;
-import static org.taverna.server.master.admin.Paths.REG_HOST;
-import static org.taverna.server.master.admin.Paths.REG_JAR;
-import static org.taverna.server.master.admin.Paths.REG_POLL;
-import static org.taverna.server.master.admin.Paths.REG_PORT;
-import static org.taverna.server.master.admin.Paths.REG_WAIT;
-import static org.taverna.server.master.admin.Paths.ROOT;
-import static org.taverna.server.master.admin.Paths.RUNS;
-import static org.taverna.server.master.admin.Paths.RUN_LIMIT;
-import static org.taverna.server.master.admin.Paths.STARTUP;
-import static org.taverna.server.master.admin.Paths.TOTAL_RUNS;
-import static org.taverna.server.master.admin.Paths.URS;
-import static org.taverna.server.master.admin.Paths.UR_FILE;
-import static org.taverna.server.master.admin.Paths.USER;
-import static org.taverna.server.master.admin.Paths.USERS;
-import static org.taverna.server.master.admin.Types.JSON;
-import static org.taverna.server.master.admin.Types.PLAIN;
-import static org.taverna.server.master.admin.Types.XML;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-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.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.ogf.usage.JobUsageRecord;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-
-/**
- * The administration interface for Taverna Server.
- * 
- * @author Donal Fellows
- */
-@Description("Administration interface for Taverna Server.")
-public interface Admin {
-	/**
-	 * Get a simple administration user interface.
-	 * 
-	 * @return The description document in a response.
-	 * @throws IOException
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces("text/html")
-	@Nonnull
-	Response getUserInterface() throws IOException;
-
-	/**
-	 * Gets support resources for the administration user interface.
-	 * 
-	 * @param file
-	 *            The name of the static resource to provide.
-	 * @return The requested document in a response.
-	 * @throws IOException
-	 */
-	@GET
-	@Path("static/{file}")
-	@Produces("*/*")
-	Response getStaticResource(@PathParam("file") String file)
-			throws IOException;
-
-	/**
-	 * Get a description of the administration interface.
-	 * 
-	 * @param ui
-	 *            What URI was used to access this resource?
-	 * @return The description document.
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces({ XML, JSON })
-	@Nonnull
-	AdminDescription getDescription(@Context UriInfo ui);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ROOT)
-	Response optionsRoot();
-
-	/**
-	 * Get whether to allow new workflow runs to be created.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(ALLOW_NEW)
-	@Produces(PLAIN)
-	@Description("Whether to allow new workflow runs to be created.")
-	boolean getAllowNew();
-
-	/**
-	 * Set whether to allow new workflow runs to be created.
-	 * 
-	 * @param newValue
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(ALLOW_NEW)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to allow new workflow runs to be created.")
-	boolean setAllowNew(boolean newValue);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ALLOW_NEW)
-	@Description("Whether to allow new workflow runs to be created.")
-	Response optionsAllowNew();
-
-	/**
-	 * Get whether to log the workflows submitted.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LOG_WFS)
-	@Produces(PLAIN)
-	@Description("Whether to log the workflows submitted.")
-	boolean getLogWorkflows();
-
-	/**
-	 * Set whether to log the workflows submitted.
-	 * 
-	 * @param logWorkflows
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LOG_WFS)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to log the workflows submitted.")
-	boolean setLogWorkflows(boolean logWorkflows);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LOG_WFS)
-	@Description("Whether to log the workflows submitted.")
-	Response optionsLogWorkflows();
-
-	/**
-	 * Get whether to log the user-directed faults.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LOG_EXN)
-	@Produces(PLAIN)
-	@Description("Whether to log the user-directed faults.")
-	boolean getLogFaults();
-
-	/**
-	 * Set whether to log the user-directed faults.
-	 * 
-	 * @param logFaults
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LOG_EXN)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Whether to log the user-directed faults.")
-	boolean setLogFaults(boolean logFaults);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LOG_EXN)
-	@Description("Whether to log the user-directed faults.")
-	Response optionsLogFaults();
-
-	/**
-	 * Get what file to dump usage records to.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(UR_FILE)
-	@Produces(PLAIN)
-	@Description("What file to dump usage records to.")
-	@Nonnull
-	String getURFile();
-
-	/**
-	 * Set what file to dump usage records to.
-	 * 
-	 * @param urFile
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(UR_FILE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What file to dump usage records to.")
-	@Nonnull
-	String setURFile(@Nonnull String urFile);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(UR_FILE)
-	@Description("What file to dump usage records to.")
-	Response optionsURFile();
-
-	/**
-	 * The property for the number of times the service methods have been
-	 * invoked.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(INVOKES)
-	@Produces(PLAIN)
-	@Description("How many times have the service methods been invoked.")
-	int invokeCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(INVOKES)
-	@Description("How many times have the service methods been invoked.")
-	Response optionsInvokationCount();
-
-	/**
-	 * The property for the number of runs that are currently in existence.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(TOTAL_RUNS)
-	@Produces(PLAIN)
-	@Description("How many runs are currently in existence.")
-	int runCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(TOTAL_RUNS)
-	@Description("How many runs are currently in existence.")
-	Response optionsRunCount();
-
-	/**
-	 * The property for the number of runs that are currently running.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(OPERATING)
-	@Produces(PLAIN)
-	@Description("How many runs are currently actually running.")
-	int operatingCount();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(OPERATING)
-	@Description("How many runs are currently actually running.")
-	Response optionsOperatingCount();
-
-	/**
-	 * Get the full pathname of the RMI registry's JAR.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_JAR)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
-	@Nonnull
-	String getRegistryJar();
-
-	/**
-	 * Set the full pathname of the RMI registry's JAR.
-	 * 
-	 * @param registryJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_JAR)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
-	@Nonnull
-	String setRegistryJar(@Nonnull String registryJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_JAR)
-	@Description("What is the full pathname of the server's special custom RMI registry executable JAR file?")
-	Response optionsRegistryJar();
-
-	/**
-	 * Get the location of the RMI registry.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_HOST)
-	@Produces(PLAIN)
-	@Description("Where is the RMI registry?")
-	@Nonnull
-	String getRegistryHost();
-
-	/**
-	 * Set the location of the RMI registry.
-	 * 
-	 * @param registryHost
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_HOST)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Where is the RMI registry?")
-	@Nonnull
-	String setRegistryHost(@Nonnull String registryHost);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_HOST)
-	@Description("Where is the RMI registry?")
-	Response optionsRegistryHost();
-
-	/**
-	 * Get the port of the RMI registry.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_PORT)
-	@Produces(PLAIN)
-	@Description("On what port is the RMI registry?")
-	int getRegistryPort();
-
-	/**
-	 * Set the port of the RMI registry.
-	 * 
-	 * @param registryPort
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_PORT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("On what port is the RMI registry?")
-	int setRegistryPort(int registryPort);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_PORT)
-	@Description("On what port is the RMI registry?")
-	Response optionsRegistryPort();
-
-	/**
-	 * Get the maximum number of simultaneous runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(RUN_LIMIT)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous runs?")
-	int getRunLimit();
-
-	/**
-	 * Set the maximum number of simultaneous runs.
-	 * 
-	 * @param runLimit
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(RUN_LIMIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous runs?")
-	int setRunLimit(int runLimit);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(RUN_LIMIT)
-	@Description("What is the maximum number of simultaneous runs?")
-	Response optionsRunLimit();
-
-	/**
-	 * Get the maximum number of simultaneous executing runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(OP_LIMIT)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	int getOperatingLimit();
-
-	/**
-	 * Set the maximum number of simultaneous executing runs.
-	 * 
-	 * @param operatingLimit
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(OP_LIMIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	int setOperatingLimit(int operatingLimit);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(OP_LIMIT)
-	@Description("What is the maximum number of simultaneous executing runs?")
-	Response optionsOperatingLimit();
-
-	/**
-	 * Get the default lifetime of workflow runs.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(LIFE)
-	@Produces(PLAIN)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	int getDefaultLifetime();
-
-	/**
-	 * Set the default lifetime of workflow runs.
-	 * 
-	 * @param defaultLifetime
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(LIFE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	int setDefaultLifetime(int defaultLifetime);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(LIFE)
-	@Description("What is the default lifetime of workflow runs, in seconds?")
-	Response optionsDefaultLifetime();
-
-	/**
-	 * The property for the list of IDs of current runs.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(RUNS)
-	@Produces({ XML, JSON })
-	@Description("List the IDs of all current runs.")
-	StringList currentRuns();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(RUNS)
-	@Description("List the IDs of all current runs.")
-	Response optionsCurrentRuns();
-
-	/**
-	 * Get the Java binary to be used for execution of subprocesses.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAVA)
-	@Produces(PLAIN)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	@Nonnull
-	String getJavaBinary();
-
-	/**
-	 * Set the Java binary to be used for execution of subprocesses.
-	 * 
-	 * @param javaBinary
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAVA)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	@Nonnull
-	String setJavaBinary(@Nonnull String javaBinary);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAVA)
-	@Description("Which Java binary should be used for execution of subprocesses?")
-	Response optionsJavaBinary();
-
-	/**
-	 * Get the extra arguments to be supplied to Java subprocesses.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(ARGS)
-	@Produces({ XML, JSON })
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	@Nonnull
-	StringList getExtraArguments();
-
-	/**
-	 * Set the extra arguments to be supplied to Java subprocesses.
-	 * 
-	 * @param extraArguments
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(ARGS)
-	@Consumes(XML)
-	@Produces({ XML, JSON })
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	@Nonnull
-	StringList setExtraArguments(@Nonnull StringList extraArguments);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(ARGS)
-	@Description("What extra arguments should be supplied to Java subprocesses?")
-	Response optionsExtraArguments();
-
-	/**
-	 * Get the full pathname of the worker JAR file.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAR_WORKER)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	@Nonnull
-	String getServerWorkerJar();
-
-	/**
-	 * Set the full pathname of the worker JAR file.
-	 * 
-	 * @param serverWorkerJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAR_WORKER)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	@Nonnull
-	String setServerWorkerJar(@Nonnull String serverWorkerJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAR_WORKER)
-	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
-	Response optionsServerWorkerJar();
-
-	/**
-	 * Get the full pathname of the executeWorkflow.sh file.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(EXEC_WF)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	@Nonnull
-	String getExecuteWorkflowScript();
-
-	/**
-	 * Set the full pathname of the executeWorkflow.sh file.
-	 * 
-	 * @param executeWorkflowScript
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(EXEC_WF)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	@Nonnull
-	String setExecuteWorkflowScript(@Nonnull String executeWorkflowScript);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(EXEC_WF)
-	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
-	Response optionsExecuteWorkflowScript();
-
-	/**
-	 * Get the total duration of time to wait for the start of the forker
-	 * process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_WAIT)
-	@Produces(PLAIN)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	int getRegistrationWaitSeconds();
-
-	/**
-	 * Set the total duration of time to wait for the start of the forker
-	 * process.
-	 * 
-	 * @param registrationWaitSeconds
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_WAIT)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	int setRegistrationWaitSeconds(int registrationWaitSeconds);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_WAIT)
-	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
-	Response optionsRegistrationWaitSeconds();
-
-	/**
-	 * Get the interval between checks for registration of the forker process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(REG_POLL)
-	@Produces(PLAIN)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	int getRegistrationPollMillis();
-
-	/**
-	 * Set the interval between checks for registration of the forker process.
-	 * 
-	 * @param registrationPollMillis
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(REG_POLL)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	int setRegistrationPollMillis(int registrationPollMillis);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(REG_POLL)
-	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
-	Response optionsRegistrationPollMillis();
-
-	/**
-	 * Get the full pathname of the file containing the impersonation
-	 * credentials for the forker process.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(PASSFILE)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	@Nonnull
-	String getRunasPasswordFile();
-
-	/**
-	 * Set the full pathname of the file containing the impersonation
-	 * credentials for the forker process.
-	 * 
-	 * @param runasPasswordFile
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(PASSFILE)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	@Nonnull
-	String setRunasPasswordFile(@Nonnull String runasPasswordFile);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(PASSFILE)
-	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
-	Response optionsRunasPasswordFile();
-
-	/**
-	 * Get the full pathname of the forker's JAR.
-	 * 
-	 * @return The current setting.
-	 */
-	@GET
-	@Path(JAR_FORKER)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	@Nonnull
-	String getServerForkerJar();
-
-	/**
-	 * Set the full pathname of the forker's JAR.
-	 * 
-	 * @param serverForkerJar
-	 *            What to set it to.
-	 * @return The new setting.
-	 */
-	@PUT
-	@Path(JAR_FORKER)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	@Nonnull
-	String setServerForkerJar(@Nonnull String serverForkerJar);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(JAR_FORKER)
-	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
-	Response optionsServerForkerJar();
-
-	/**
-	 * The property for the length of time it took to start the forker.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(STARTUP)
-	@Produces(PLAIN)
-	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
-	int startupTime();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(STARTUP)
-	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
-	Response optionsStartupTime();
-
-	/**
-	 * The property for the last exit code of the forker process.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(EXITCODE)
-	@Produces(PLAIN)
-	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
-	Integer lastExitCode();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(EXITCODE)
-	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
-	Response optionsLastExitCode();
-
-	/**
-	 * The property for the mapping of usernames to factory process handles.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(FACTORIES)
-	@Produces({ XML, JSON })
-	@Description("What is the mapping of local usernames to factory process RMI IDs?")
-	StringList factoryProcessMapping();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(FACTORIES)
-	@Description("What is the mapping of local usernames to factory process RMI IDs?")
-	Response optionsFactoryProcessMapping();
-
-	/**
-	 * The property for the list of usage records collected.
-	 * 
-	 * @return The property value (read-only).
-	 */
-	@GET
-	@Path(URS)
-	@Produces(XML)
-	@Description("What is the list of usage records that have been collected?")
-	URList usageRecords();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(URS)
-	@Description("What is the list of usage records that have been collected?")
-	Response optionsUsageRecords();
-
-	/**
-	 * What are the current list of workflow URIs that may be started? Empty
-	 * means allow any, including user-supplied workflows.
-	 * 
-	 * @return List of URIs, encoded as strings.
-	 */
-	@GET
-	@Path(PERM_WF)
-	@Produces({ XML, JSON })
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	StringList getPermittedWorkflowURIs();
-
-	/** Do we turn on the generate provenance option by default? */
-	@GET
-	@Path(GEN_PROV)
-	@Produces(PLAIN)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	String getGenerateProvenance();
-
-	/** Do we turn on the generate provenance option by default? */
-	@PUT
-	@Path(GEN_PROV)
-	@Consumes(PLAIN)
-	@Produces(PLAIN)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	String setGenerateProvenance(String newValue);
-
-	/** Do we turn on the generate provenance option by default? */
-	@OPTIONS
-	@Path(GEN_PROV)
-	@Description("Do we turn on the generate provenance option by default? (boolean)")
-	Response optionsGenerateProvenance();
-
-	/**
-	 * What are the current list of workflow URIs that may be started? Empty
-	 * means allow any, including user-supplied workflows.
-	 * 
-	 * @param permitted
-	 *            List of URIs, encoded as strings.
-	 * @return List of URIs, encoded as strings.
-	 */
-	@PUT
-	@Path(PERM_WF)
-	@Consumes(XML)
-	@Produces({ XML, JSON })
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	StringList setPermittedWorkflowURIs(@Nonnull StringList permitted);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(PERM_WF)
-	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
-	Response optionsPermittedWorkflowURIs();
-
-	@GET
-	@Path(USERS)
-	@Produces({ XML, JSON })
-	@Description("What users are known to the server?")
-	UserList users(@Context UriInfo ui);
-
-	@GET
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Description("What do we know about a particular user?")
-	UserDesc user(@PathParam("id") String username);
-
-	@POST
-	@Path(USERS)
-	@Consumes(XML)
-	@Description("Create a user.")
-	Response useradd(UserDesc userdesc, @Nonnull @Context UriInfo ui);
-
-	@PUT
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Consumes(XML)
-	@Description("Update a user.")
-	UserDesc userset(@PathParam("id") String username, UserDesc userdesc);
-
-	@DELETE
-	@Path(USER)
-	@Produces({ XML, JSON })
-	@Description("What do we know about a particular user?")
-	Response userdel(@PathParam("id") String username);
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(USERS)
-	@Description("What users are known to the server?")
-	Response optionsUsers();
-
-	/** What HTTP methods may we use? */
-	@OPTIONS
-	@Path(USER)
-	@Description("What do we know about a particular user?")
-	Response optionsUser(@PathParam("id") String username);
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * The description of what properties are supported by the administration
-	 * interface.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "description")
-	@XmlType(name = "Description")
-	public static class AdminDescription extends VersionedElement {
-		public Uri allowNew;
-		public Uri logWorkflows;
-		public Uri logFaults;
-		public Uri usageRecordDumpFile;
-		public Uri invokationCount;
-		public Uri runCount;
-		public Uri registryHost;
-		public Uri registryPort;
-		public Uri runLimit;
-		public Uri defaultLifetime;
-		public Uri currentRuns;
-		public Uri javaBinary;
-		public Uri extraArguments;
-		public Uri serverWorkerJar;
-		public Uri serverForkerJar;
-		public Uri executeWorkflowScript;
-		public Uri registrationWaitSeconds;
-		public Uri registrationPollMillis;
-		public Uri runasPasswordFile;
-		public Uri startupTime;
-		public Uri lastExitCode;
-		public Uri factoryProcessMapping;
-		public Uri usageRecords;
-		public Uri users;
-		public Uri operatingLimit;
-		public Uri operatingCount;
-		public Uri permittedWorkflowURIs;
-		public Uri generateProvenance;
-
-		public AdminDescription() {
-		}
-
-		public AdminDescription(UriInfo ui) {
-			allowNew = new Uri(ui, ALLOW_NEW);
-			logWorkflows = new Uri(ui, LOG_WFS);
-			logFaults = new Uri(ui, LOG_EXN);
-			usageRecordDumpFile = new Uri(ui, UR_FILE);
-			invokationCount = new Uri(ui, INVOKES);
-			runCount = new Uri(ui, TOTAL_RUNS);
-			registryHost = new Uri(ui, REG_HOST);
-			registryPort = new Uri(ui, REG_PORT);
-			runLimit = new Uri(ui, RUN_LIMIT);
-			defaultLifetime = new Uri(ui, LIFE);
-			currentRuns = new Uri(ui, RUNS);
-			javaBinary = new Uri(ui, JAVA);
-			extraArguments = new Uri(ui, ARGS);
-			serverWorkerJar = new Uri(ui, JAR_WORKER);
-			serverForkerJar = new Uri(ui, JAR_FORKER);
-			executeWorkflowScript = new Uri(ui, EXEC_WF);
-			registrationWaitSeconds = new Uri(ui, REG_WAIT);
-			registrationPollMillis = new Uri(ui, REG_POLL);
-			runasPasswordFile = new Uri(ui, PASSFILE);
-			startupTime = new Uri(ui, STARTUP);
-			lastExitCode = new Uri(ui, EXITCODE);
-			factoryProcessMapping = new Uri(ui, FACTORIES);
-			usageRecords = new Uri(ui, URS);
-			users = new Uri(ui, USERS);
-			operatingLimit = new Uri(ui, OP_LIMIT);
-			operatingCount = new Uri(ui, OPERATING);
-			permittedWorkflowURIs = new Uri(ui, PERM_WF);
-			generateProvenance = new Uri(ui, GEN_PROV);
-		}
-	}
-
-	/**
-	 * A list of strings, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "stringList")
-	@XmlType(name = "StringList")
-	public static class StringList {
-		@XmlElement
-		public List<String> string = new ArrayList<>();
-	}
-
-	/**
-	 * A list of users, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "userList")
-	@XmlType(name = "UserList")
-	public static class UserList {
-		@XmlElement
-		public List<URI> user = new ArrayList<>();
-	}
-
-	@XmlRootElement(name = "userDesc")
-	@XmlType(name = "UserDesc")
-	public static class UserDesc {
-		@XmlElement
-		public String username;
-		@XmlElement
-		public String password;
-		@XmlElement
-		public String localUserId;
-		@XmlElement
-		public Boolean enabled;
-		@XmlElement
-		public Boolean admin;
-	}
-
-	/**
-	 * A list of usage records, as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "usageRecordList")
-	@XmlType(name = "UsageRecords")
-	public static class URList {
-		@XmlElement
-		public List<JobUsageRecord> usageRecord;
-	}
-}
-
-interface Paths {
-	static final String ROOT = "/";
-	static final String ALLOW_NEW = "allowNew";
-	static final String LOG_WFS = "logWorkflows";
-	static final String LOG_EXN = "logFaults";
-	static final String UR_FILE = "usageRecordDumpFile";
-	static final String INVOKES = "invokationCount";
-	static final String TOTAL_RUNS = "runCount";
-	static final String OPERATING = "operatingCount";
-	static final String REG_HOST = "registryHost";
-	static final String REG_PORT = "registryPort";
-	static final String REG_JAR = "registryJar";
-	static final String RUN_LIMIT = "runLimit";
-	static final String OP_LIMIT = "operatingLimit";
-	static final String LIFE = "defaultLifetime";
-	static final String RUNS = "currentRuns";
-	static final String JAVA = "javaBinary";
-	static final String ARGS = "extraArguments";
-	static final String JAR_WORKER = "serverWorkerJar";
-	static final String JAR_FORKER = "serverForkerJar";
-	static final String EXEC_WF = "executeWorkflowScript";
-	static final String REG_WAIT = "registrationWaitSeconds";
-	static final String REG_POLL = "registrationPollMillis";
-	static final String PASSFILE = "runasPasswordFile";
-	static final String STARTUP = "startupTime";
-	static final String EXITCODE = "lastExitCode";
-	static final String FACTORIES = "factoryProcessMapping";
-	static final String URS = "usageRecords";
-	static final String PERM_WF = "permittedWorkflowURIs";
-	static final String GEN_PROV = "generateProvenance";
-	static final String USERS = "users";
-	static final String USER = USERS + "/{id}";
-}
-
-interface Types {
-	static final String PLAIN = "text/plain";
-	static final String XML = "application/xml";
-	static final String JSON = "application/json";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java b/server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
deleted file mode 100644
index b83d88f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.admin;
-
-import static java.util.Arrays.asList;
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-import static org.taverna.server.master.common.Roles.ADMIN;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.exceptions.GeneralFailureException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.identity.User;
-import org.taverna.server.master.identity.UserStoreAPI;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.InvocationCounter;
-import org.taverna.server.master.worker.RunDBSupport;
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The administration interface to Taverna Server.
- * 
- * @author Donal Fellows
- */
-public class AdminBean implements Admin {
-	@Required
-	public void setState(ManagementModel state) {
-		this.state = state;
-	}
-
-	@Required
-	public void setCounter(InvocationCounter counter) {
-		this.counter = counter;
-	}
-
-	@Required
-	public void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	@Required
-	public void setFactory(ConfigurableRunFactory factory) {
-		this.factory = factory;
-	}
-
-	@Required
-	public void setUsageRecords(UsageRecordRecorder usageRecords) {
-		this.usageRecords = usageRecords;
-	}
-
-	@Required
-	public void setUserStore(UserStoreAPI userStore) {
-		this.userStore = userStore;
-	}
-
-	@Required
-	public void setLocalWorkerModel(WorkerModel worker) {
-		localWorker = worker;
-	}
-
-	public void setAdminHtmlFile(String filename) {
-		this.adminHtmlFile = filename;
-	}
-
-	public void setResourceRoot(String root) {
-		this.resourceRoot = root;
-	}
-
-	protected byte[] getResource(String name) throws IOException {
-		if (AdminBean.class.getResource(name) == null)
-			throw new FileNotFoundException(name);
-		return IOUtils.toByteArray(AdminBean.class.getResourceAsStream(name));
-	}
-
-	private ManagementModel state;
-	private InvocationCounter counter;
-	private RunDBSupport runDB;
-	private ConfigurableRunFactory factory;
-	private UsageRecordRecorder usageRecords;
-	private UserStoreAPI userStore;
-	private WorkerModel localWorker;
-	private String adminHtmlFile = "/admin.html";
-	private String resourceRoot = "/static/";
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response getUserInterface() throws IOException {
-		return Response.ok(getResource(adminHtmlFile), "text/html").build();
-	}
-
-	@Override
-	@RolesAllowed(ADMIN)
-	public Response getStaticResource(String file) throws IOException {
-		if (file.matches("^[-_.a-zA-Z0-9]+$")) {
-			String type = "application/octet-stream";
-			if (file.endsWith(".html"))
-				type = "text/html";
-			else if (file.endsWith(".js"))
-				type = "text/javascript";
-			else if (file.endsWith(".jpg"))
-				type = "image/jpeg";
-			else if (file.endsWith(".gif"))
-				type = "image/gif";
-			else if (file.endsWith(".png"))
-				type = "image/png";
-			else if (file.endsWith(".svg"))
-				type = "image/svg+xml";
-			else if (file.endsWith(".css"))
-				type = "text/css";
-			try {
-				return Response.ok(getResource(resourceRoot + file), type)
-						.build();
-			} catch (IOException e) {
-				// ignore; we just treat as 404
-			}
-		}
-		return Response.status(NOT_FOUND).entity("no such resource").build();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public AdminDescription getDescription(UriInfo ui) {
-		return new AdminDescription(ui);
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRoot() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getAllowNew() {
-		return state.getAllowNewWorkflowRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setAllowNew(boolean newValue) {
-		state.setAllowNewWorkflowRuns(newValue);
-		return state.getAllowNewWorkflowRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsAllowNew() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getLogWorkflows() {
-		return state.getLogIncomingWorkflows();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setLogWorkflows(boolean newValue) {
-		state.setLogIncomingWorkflows(newValue);
-		return state.getLogIncomingWorkflows();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLogWorkflows() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean getLogFaults() {
-		return state.getLogOutgoingExceptions();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public boolean setLogFaults(boolean newValue) {
-		state.setLogOutgoingExceptions(newValue);
-		return state.getLogOutgoingExceptions();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLogFaults() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getURFile() {
-		return state.getUsageRecordLogFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setURFile(String newValue) {
-		state.setUsageRecordLogFile(newValue);
-		return state.getUsageRecordLogFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsURFile() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int invokeCount() {
-		return counter.getCount();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsInvokationCount() {
-		return opt();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int runCount() {
-		return runDB.countRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRunCount() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRegistryHost() {
-		return factory.getRegistryHost();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRegistryHost(String newValue) {
-		factory.setRegistryHost(newValue);
-		return factory.getRegistryHost();
-	}
-
-	@Override
-	public Response optionsRegistryHost() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistryPort() {
-		return factory.getRegistryPort();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistryPort(int newValue) {
-		factory.setRegistryPort(newValue);
-		return factory.getRegistryPort();
-	}
-
-	@Override
-	public Response optionsRegistryPort() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRegistryJar() {
-		return factory.getRmiRegistryJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRegistryJar(String registryJar) {
-		factory.setRmiRegistryJar(registryJar);
-		return factory.getRmiRegistryJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistryJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRunLimit() {
-		return factory.getMaxRuns();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRunLimit(int newValue) {
-		factory.setMaxRuns(newValue);
-		return factory.getMaxRuns();
-	}
-
-	@Override
-	public Response optionsRunLimit() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getDefaultLifetime() {
-		return factory.getDefaultLifetime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setDefaultLifetime(int newValue) {
-		factory.setDefaultLifetime(newValue);
-		return factory.getDefaultLifetime();
-	}
-
-	@Override
-	public Response optionsDefaultLifetime() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList currentRuns() {
-		StringList result = new StringList();
-		result.string = runDB.listRunNames();
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsCurrentRuns() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getJavaBinary() {
-		return factory.getJavaBinary();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setJavaBinary(String newValue) {
-		factory.setJavaBinary(newValue);
-		return factory.getJavaBinary();
-	}
-
-	@Override
-	public Response optionsJavaBinary() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList getExtraArguments() {
-		String[] xargs = factory.getExtraArguments();
-		StringList result = new StringList();
-		result.string = asList(xargs == null ? new String[0] : xargs);
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList setExtraArguments(StringList newValue) {
-		if (newValue == null || newValue.string == null)
-			factory.setExtraArguments(new String[0]);
-		else
-			factory.setExtraArguments(newValue.string
-					.toArray(new String[newValue.string.size()]));
-		StringList result = new StringList();
-		result.string = asList(factory.getExtraArguments());
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsExtraArguments() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getServerWorkerJar() {
-		return factory.getServerWorkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setServerWorkerJar(String newValue) {
-		factory.setServerWorkerJar(newValue);
-		return factory.getServerWorkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsServerWorkerJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getExecuteWorkflowScript() {
-		return factory.getExecuteWorkflowScript();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setExecuteWorkflowScript(String newValue) {
-		factory.setExecuteWorkflowScript(newValue);
-		return factory.getExecuteWorkflowScript();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsExecuteWorkflowScript() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistrationWaitSeconds() {
-		return factory.getWaitSeconds();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistrationWaitSeconds(int newValue) {
-		factory.setWaitSeconds(newValue);
-		return factory.getWaitSeconds();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistrationWaitSeconds() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getRegistrationPollMillis() {
-		return factory.getSleepTime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setRegistrationPollMillis(int newValue) {
-		factory.setSleepTime(newValue);
-		return factory.getSleepTime();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRegistrationPollMillis() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getRunasPasswordFile() {
-		return factory.getPasswordFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setRunasPasswordFile(String newValue) {
-		factory.setPasswordFile(newValue);
-		return factory.getPasswordFile();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsRunasPasswordFile() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getServerForkerJar() {
-		return factory.getServerForkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setServerForkerJar(String newValue) {
-		factory.setServerForkerJar(newValue);
-		return factory.getServerForkerJar();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsServerForkerJar() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int startupTime() {
-		return factory.getLastStartupCheckCount();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsStartupTime() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Integer lastExitCode() {
-		return factory.getLastExitCode();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsLastExitCode() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList factoryProcessMapping() {
-		StringList result = new StringList();
-		result.string = asList(factory.getFactoryProcessMapping());
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsFactoryProcessMapping() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public URList usageRecords() {
-		URList result = new URList();
-		result.usageRecord = usageRecords.getUsageRecords();
-		return result;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUsageRecords() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserList users(UriInfo ui) {
-		UserList ul = new UserList();
-		UriBuilder ub = secure(ui).path("{id}");
-		for (String user : userStore.getUserNames())
-			ul.user.add(ub.build(user));
-		return ul;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUsers() {
-		return opt("POST");
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserDesc user(String username) {
-		UserDesc desc = new UserDesc();
-		User u = userStore.getUser(username);
-		desc.username = u.getUsername();
-		desc.localUserId = u.getLocalUsername();
-		desc.admin = u.isAdmin();
-		desc.enabled = u.isEnabled();
-		return desc;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsUser(String username) {
-		return opt("PUT", "DELETE");
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response useradd(UserDesc userdesc, UriInfo ui) {
-		if (userdesc.username == null)
-			throw new IllegalArgumentException("no user name supplied");
-		if (userdesc.password == null)
-			userdesc.password = randomUUID().toString();
-		userStore.addUser(userdesc.username, userdesc.password, false);
-		if (userdesc.localUserId != null)
-			userStore.setUserLocalUser(userdesc.username, userdesc.localUserId);
-		if (userdesc.admin != null && userdesc.admin)
-			userStore.setUserAdmin(userdesc.username, true);
-		if (userdesc.enabled != null && userdesc.enabled)
-			userStore.setUserEnabled(userdesc.username, true);
-		return created(secure(ui).path("{id}").build(userdesc.username))
-				.build();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public UserDesc userset(String username, UserDesc userdesc) {
-		if (userdesc.password != null)
-			userStore.setUserPassword(username, userdesc.password);
-		if (userdesc.localUserId != null)
-			userStore.setUserLocalUser(username, userdesc.localUserId);
-		if (userdesc.admin != null)
-			userStore.setUserAdmin(username, userdesc.admin);
-		if (userdesc.enabled != null)
-			userStore.setUserEnabled(username, userdesc.enabled);
-		userdesc = null; // Stop reuse!
-
-		UserDesc desc = new UserDesc();
-		User u = userStore.getUser(username);
-		desc.username = u.getUsername();
-		desc.localUserId = u.getLocalUsername();
-		desc.admin = u.isAdmin();
-		desc.enabled = u.isEnabled();
-		return desc;
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response userdel(String username) {
-		userStore.deleteUser(username);
-		return noContent().build();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int operatingCount() {
-		try {
-			return factory.getOperatingCount();
-		} catch (Exception e) {
-			throw new GeneralFailureException(e);
-		}
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsOperatingCount() {
-		return opt();
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int getOperatingLimit() {
-		return factory.getOperatingLimit();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public int setOperatingLimit(int operatingLimit) {
-		factory.setOperatingLimit(operatingLimit);
-		return factory.getOperatingLimit();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsOperatingLimit() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList getPermittedWorkflowURIs() {
-		StringList sl = new StringList();
-		List<URI> uris = localWorker.getPermittedWorkflowURIs();
-		if (uris != null)
-			for (URI uri : uris)
-				sl.string.add(uri.toString());
-		return sl;
-	}
-
-	private static final URI myExp = URI.create("http://www.myexperment.org/");
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public StringList setPermittedWorkflowURIs(StringList permitted) {
-		List<URI> uris = new ArrayList<>();
-		for (String uri : permitted.string)
-			try {
-				uris.add(myExp.resolve(uri));
-			} catch (Exception e) {
-				// Ignore
-			}
-		localWorker.setPermittedWorkflowURIs(uris);
-		return getPermittedWorkflowURIs();
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsPermittedWorkflowURIs() {
-		return opt("PUT");
-	}
-
-	// /////////////////////////////////////////////////////
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String getGenerateProvenance() {
-		return Boolean.toString(localWorker.getGenerateProvenance());
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public String setGenerateProvenance(String newValue) {
-		boolean b = Boolean.parseBoolean(newValue);
-		localWorker.setGenerateProvenance(b);
-		return Boolean.toString(localWorker.getGenerateProvenance());
-	}
-
-	@RolesAllowed(ADMIN)
-	@Override
-	public Response optionsGenerateProvenance() {
-		return opt("PUT");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
deleted file mode 100644
index 930fd75..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the RESTful administration interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = ADMIN, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN),
-		@XmlNs(prefix = "ur", namespaceURI = UR),
-		@XmlNs(prefix = "ds", namespaceURI = XSIG) })
-package org.taverna.server.master.admin;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.UR;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.Namespaces.XSIG;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java b/server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
deleted file mode 100644
index 1a89b8d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.api;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
-
-import java.util.List;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Variant;
-
-/**
- * The content types supported at various points in the REST interface.
- * 
- * @author Donal Fellows
- */
-public interface ContentTypes {
-	/** "application/zip" */
-	public static final MediaType APPLICATION_ZIP_TYPE = new MediaType(
-			"application", "zip");
-
-	/** "application/vnd.taverna.baclava+xml" */
-	public static final MediaType BACLAVA_MEDIA_TYPE = new MediaType(
-			"application", "vnd.taverna.baclava+xml");
-
-	/**
-	 * The media types that we are willing to serve up directories as. Note that
-	 * we <i>only</i> serve directories up as these.
-	 */
-	public static final List<Variant> DIRECTORY_VARIANTS = asList(new Variant(
-			APPLICATION_XML_TYPE, (String) null, "UTF-8"), new Variant(
-			APPLICATION_JSON_TYPE, (String) null, "UTF-8"), new Variant(
-			APPLICATION_ZIP_TYPE, (String) null, null));
-
-	/**
-	 * The baseline set of media types that we are willing to serve up files as.
-	 * Note that we <i>also</i> serve files up as their auto-detected media
-	 * type. In all cases, this means we just shovel the bytes (or characters,
-	 * in the case of <tt>text/*</tt> subtypes) back at the client.
-	 */
-	public static final List<Variant> INITIAL_FILE_VARIANTS = singletonList(new Variant(
-			APPLICATION_OCTET_STREAM_TYPE, (String) null, null));
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
deleted file mode 100644
index 8fa5c78..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Description of properties supported by {@link DirectoryREST}.
- * 
- * @author Donal Fellows
- */
-public interface DirectoryBean extends SupportAware {
-	void setFileUtils(FilenameUtils fileUtils);
-
-	TavernaServerDirectoryREST connect(TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
deleted file mode 100644
index 5ace6a3..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.InteractionFeed;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-
-/**
- * Description of properties supported by {@link InteractionFeed}.
- * 
- * @author Donal Fellows
- */
-public interface FeedBean {
-	void setInteractionFeedSupport(InteractionFeedSupport feed);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
deleted file mode 100644
index eecea44..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.taverna.server.master.api;
-
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * Description of properties supported by {@link InputREST}.
- * 
- * @author Donal Fellows
- */
-public interface InputBean extends SupportAware {
-	TavernaServerInputREST connect(TavernaRun run, UriInfo ui);
-
-	void setCdBuilder(ContentsDescriptorBuilder cd);
-
-	void setFileUtils(FilenameUtils fn);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
deleted file mode 100644
index 5c480d4..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-
-/**
- * Description of properties supported by {@link ListenerPropertyREST}.
- * 
- * @author Donal Fellows
- */
-public interface ListenerPropertyBean extends SupportAware {
-	TavernaServerListenersREST.Property connect(Listener listen,
-			TavernaRun run, String propertyName);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
deleted file mode 100644
index c02bf62..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-
-/**
- * Description of properties supported by {@link ListenersREST}.
- * 
- * @author Donal Fellows
- */
-public interface ListenersBean extends SupportAware {
-	TavernaServerListenersREST connect(TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java b/server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
deleted file mode 100644
index 6bc6058..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.api;
-
-/**
- * The model of the webapp's state Java Bean.
- * 
- * @author Donal Fellows
- */
-public interface ManagementModel {
-	/**
-	 * @return whether we allow the creation of new workflow runs.
-	 */
-	boolean getAllowNewWorkflowRuns();
-
-	/**
-	 * @return whether we should log all workflows sent to us.
-	 */
-	boolean getLogIncomingWorkflows();
-
-	/**
-	 * @return whether outgoing exceptions should be logged before being
-	 *         converted to responses.
-	 */
-	boolean getLogOutgoingExceptions();
-
-	/**
-	 * @return the file that all usage records should be appended to, or
-	 *         <tt>null</tt> if they should be just dropped.
-	 */
-	String getUsageRecordLogFile();
-
-	/**
-	 * @param logIncomingWorkflows
-	 *            whether we should log all workflows sent to us.
-	 */
-	void setLogIncomingWorkflows(boolean logIncomingWorkflows);
-
-	/**
-	 * @param allowNewWorkflowRuns
-	 *            whether we allow the creation of new workflow runs.
-	 */
-	void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns);
-
-	/**
-	 * @param logOutgoingExceptions
-	 *            whether outgoing exceptions should be logged before being
-	 *            converted to responses.
-	 */
-	void setLogOutgoingExceptions(boolean logOutgoingExceptions);
-
-	/**
-	 * @param usageRecordLogFile
-	 *            the file that all usage records should be appended to, or
-	 *            <tt>null</tt> if they should be just dropped.
-	 */
-	void setUsageRecordLogFile(String usageRecordLogFile);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
deleted file mode 100644
index 9f80a12..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
-
-/**
- * Description of properties supported by {@link InputREST}.
- * 
- * @author Donal Fellows
- */
-public interface OneListenerBean {
-	TavernaServerListenerREST connect(Listener listen, TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
deleted file mode 100644
index 4903ea9..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Description of properties supported by {@link RunREST}.
- * 
- * @author Donal Fellows
- */
-public interface RunBean extends SupportAware {
-	void setCdBuilder(ContentsDescriptorBuilder cdBuilder);
-
-	void setRun(TavernaRun run);
-
-	void setRunName(String runName);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
deleted file mode 100644
index 04fbd6e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-
-/**
- * Description of properties supported by {@link RunSecurityREST}.
- * 
- * @author Donal Fellows
- */
-public interface SecurityBean extends SupportAware {
-	TavernaServerSecurityREST connect(TavernaSecurityContext context, TavernaRun run);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java b/server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
deleted file mode 100644
index c632657..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.taverna.server.master.api;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.TavernaServerSupport;
-
-/**
- * Indicates that this is a class that wants to be told by Spring about the
- * main support bean.
- * 
- * @author Donal Fellows
- */
-public interface SupportAware {
-	/**
-	 * How to tell the bean about the support bean.
-	 * 
-	 * @param support
-	 *            Reference to the support bean.
-	 */
-	@Required
-	void setSupport(TavernaServerSupport support);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java b/server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
deleted file mode 100644
index 5a14fb6..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.api;
-
-import javax.annotation.Nonnull;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.ContentsDescriptorBuilder;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.RunStore;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-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.soap.TavernaServerSOAP;
-import org.taverna.server.master.utils.FilenameUtils;
-
-/**
- * The methods of the webapp that are accessed by beans other than itself or
- * those which are told directly about it. This exists so that an AOP proxy can
- * be installed around it.
- * 
- * @author Donal Fellows
- */
-public interface TavernaServerBean extends TavernaServerSOAP, TavernaServerREST,
-		UriBuilderFactory {
-	/**
-	 * @param policy
-	 *            The policy being installed by Spring.
-	 */
-	@Required
-	void setPolicy(@Nonnull Policy policy);
-
-	/**
-	 * @param runStore
-	 *            The run store being installed by Spring.
-	 */
-	@Required
-	void setRunStore(@Nonnull RunStore runStore);
-
-	/**
-	 * @param converter
-	 *            The filename converter being installed by Spring.
-	 */
-	@Required
-	void setFileUtils(@Nonnull FilenameUtils converter);
-
-	/**
-	 * @param cdBuilder
-	 *            The contents descriptor builder being installed by Spring.
-	 */
-	@Required
-	void setContentsDescriptorBuilder(
-			@Nonnull ContentsDescriptorBuilder cdBuilder);
-
-	/**
-	 * @param notificationEngine
-	 *            The notification engine being installed by Spring.
-	 */
-	@Required
-	void setNotificationEngine(@Nonnull NotificationEngine notificationEngine);
-
-	/**
-	 * @param support
-	 *            The support bean being installed by Spring.
-	 */
-	@Required
-	void setSupport(@Nonnull TavernaServerSupport support);
-
-	/**
-	 * @param eventSource
-	 *            The event source bean being installed by Spring.
-	 */
-	@Required
-	void setEventSource(@Nonnull EventDAO eventSource);
-
-	/**
-	 * The nastier parts of security initialisation in SOAP calls, which we want
-	 * to go away.
-	 * 
-	 * @param context
-	 *            The context to configure.
-	 * @return True if we did <i>not</i> initialise things.
-	 */
-	boolean initObsoleteSOAPSecurity(@Nonnull TavernaSecurityContext context);
-
-	/**
-	 * The nastier parts of security initialisation in REST calls, which we want
-	 * to go away.
-	 * 
-	 * @param context
-	 *            The context to configure.
-	 * @return True if we did <i>not</i> initialise things.
-	 */
-	boolean initObsoleteRESTSecurity(@Nonnull TavernaSecurityContext context);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/api/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
deleted file mode 100644
index fe76a09..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * API <tt>interface</tt>s for the main service classes.
- * 
- * @author Donal Fellows
- */
-package org.taverna.server.master.api;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Capability.java b/server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
deleted file mode 100644
index 034d489..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.taverna.server.master.common;
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Describes a single capability supported by Taverna Server's workflow
- * execution core.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Capability")
-public class Capability {
-	@XmlAttribute
-	@XmlSchemaType(name = "anyURI")
-	public URI capability;
-	@XmlAttribute
-	public String version;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Credential.java b/server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
deleted file mode 100644
index 5c16e79..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.io.Serializable;
-import java.net.URI;
-import java.security.Key;
-import java.security.cert.Certificate;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import javax.annotation.Nonnull;
-
-/**
- * A description of a private credential. This description is characterised by a
- * file visible to the workflow run that contains a particular key-pair.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "CredentialDescriptor")
-@XmlSeeAlso({ Credential.KeyPair.class, Credential.Password.class })
-@SuppressWarnings("serial")
-public abstract class Credential implements Serializable {
-	/** The location of this descriptor in the REST world. */
-	@XmlAttribute(namespace = XLINK)
-	public String href;
-	/**
-	 * The location of this descriptor in the SOAP world. Must match corrected
-	 * with the {@link #href} field.
-	 */
-	@XmlTransient
-	public String id;
-	/**
-	 * The service URI to use this credential with. If omitted, this represents
-	 * the <i>default</i> credential to use.
-	 */
-	@XmlElement
-	@XmlSchemaType(name = "anyURI")
-	public URI serviceURI;
-	/** The key extracted from the keystore. */
-	public transient Key loadedKey;
-	/** The trust chain of the key extracted from the keystore. */
-	public transient Certificate[] loadedTrustChain;
-
-	@Override
-	public int hashCode() {
-		return id.hashCode();
-	}
-
-	@Override
-	public final boolean equals(Object o) {
-		if (o == null || !(o instanceof Credential))
-			return false;
-		return equals((Credential) o);
-	}
-
-	protected boolean equals(@Nonnull Credential c) {
-		return id.equals(c.id);
-	}
-
-	/**
-	 * A description of a credential that is a public/private key-pair in some
-	 * kind of key store.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "keypair")
-	@XmlType(name = "KeyPairCredential")
-	public static class KeyPair extends Credential {
-		/** The name of the credential within its store, i.e., it's alias. */
-		@XmlElement(required = true)
-		public String credentialName;
-		/**
-		 * The keystore file containing the credential. This is resolved with
-		 * respect to the workflow run working directory.
-		 */
-		@XmlElement
-		public String credentialFile;
-		/**
-		 * The type of keystore file. Defaults to <tt>JKS</tt> if unspecified.
-		 */
-		@XmlElement
-		public String fileType;
-		/**
-		 * The password used to unlock the keystore file. It is assumed that the
-		 * same password is used for unlocking the credential within, or that
-		 * the inner password is empty.
-		 */
-		@XmlElement
-		public String unlockPassword;
-		/**
-		 * The encoded serialized keystore containing the credential.
-		 */
-		@XmlElement
-		public byte[] credentialBytes;
-
-		@Override
-		public String toString() {
-			return "keypair(id=" + id + ")";
-		}
-	}
-
-	/**
-	 * A description of a credential that is a username and password.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "userpass")
-	@XmlType(name = "PasswordCredential")
-	public static class Password extends Credential {
-		@XmlElement(required = true)
-		public String username;
-		@XmlElement(required = true)
-		public String password;
-
-		@Override
-		public String toString() {
-			return "userpass(id=" + id + ")";
-		}
-	}
-
-	/**
-	 * A credential that is just used for deleting credentials by ID. Cannot be
-	 * marshalled as XML.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class Dummy extends Credential {
-		public Dummy(String id) {
-			this.id = id;
-		}
-
-		@Override
-		public String toString() {
-			return "dummy(id=" + id + ")";
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java b/server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
deleted file mode 100644
index 318ae4f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-
-/**
- * A reference to something that is in a directory below the working directory
- * of a workflow run, described using JAXB. Note that when creating an XML
- * document containing one of these in a client, it is <i>not</i> necessary to
- * supply any attribute.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "DirectoryEntry")
-@XmlSeeAlso( { DirEntryReference.DirectoryReference.class,
-		DirEntryReference.FileReference.class })
-public class DirEntryReference {
-	/** A link to the entry. Ignored on input. */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	/** The last, user-displayable part of the name. Ignored on input. */
-	@XmlAttribute
-	public String name;
-	/** The path of the entry. */
-	@XmlValue
-	public String path;
-
-	/**
-	 * Return the directory entry reference instance subclass suitable for the
-	 * given directory entry.
-	 * 
-	 * @param entry
-	 *            The entry to characterise.
-	 * @return An object that describes the directory entry.
-	 */
-	public static DirEntryReference newInstance(DirectoryEntry entry) {
-		return newInstance(null, entry);
-	}
-
-	/**
-	 * Return the directory entry reference instance subclass suitable for the
-	 * given directory entry.
-	 * 
-	 * @param ub
-	 *            Used for constructing URIs. The {@link #link} field is not
-	 *            filled in if this is <tt>null</tt>.
-	 * @param entry
-	 *            The entry to characterise.
-	 * @return An object that describes the directory entry.
-	 */
-	// Really returns a subclass, so cannot be constructor
-	public static DirEntryReference newInstance(UriBuilder ub,
-			DirectoryEntry entry) {
-		DirEntryReference de = (entry instanceof Directory) ? new DirectoryReference()
-				: new FileReference();
-		de.name = entry.getName();
-		String fullname = entry.getFullName();
-		de.path = fullname.startsWith("/") ? fullname.substring(1) : fullname;
-		if (ub != null)
-			de.link = ub.build(entry.getName());
-		return de;
-	}
-
-	/** A reference to a directory, done with JAXB. */
-	@XmlRootElement(name = "dir")
-	@XmlType(name = "DirectoryReference")
-	public static class DirectoryReference extends DirEntryReference {
-	}
-
-	/** A reference to a file, done with JAXB. */
-	@XmlRootElement(name = "file")
-	@XmlType(name = "FileReference")
-	public static class FileReference extends DirEntryReference {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java b/server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
deleted file mode 100644
index bb98d6d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A description of the inputs to a workflow, described using JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement(name = "inputConfiguration")
-@XmlType(name = "InputConfigurationDescription")
-public class InputDescription extends VersionedElement {
-	/**
-	 * The Baclava file handling the description of the elements. May be
-	 * omitted/<tt>null</tt>.
-	 */
-	@XmlElement(required = false)
-	public String baclavaFile;
-	/**
-	 * The port/value assignment.
-	 */
-	@XmlElement(nillable = false)
-	public List<Port> port = new ArrayList<>();
-
-	/**
-	 * Make a blank input description.
-	 */
-	public InputDescription() {
-	}
-
-	/**
-	 * Make an input description suitable for the given workflow run.
-	 * 
-	 * @param run
-	 */
-	public InputDescription(TavernaRun run) {
-		super(true);
-		baclavaFile = run.getInputBaclavaFile();
-		if (baclavaFile == null)
-			for (Input i : run.getInputs())
-				port.add(new Port(i));
-	}
-
-	/**
-	 * The type of a single port description.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "PortConfigurationDescription")
-	public static class Port {
-		/**
-		 * The name of this port.
-		 */
-		@XmlAttribute(name = "portName", required = true)
-		public String name;
-		/**
-		 * The file assigned to this port.
-		 */
-		@XmlAttribute(name = "portFile", required = false)
-		public String file;
-		/**
-		 * The file assigned to this port.
-		 */
-		@XmlAttribute(name = "listDelimiter", required = false)
-		public String delimiter;
-		/**
-		 * The value assigned to this port.
-		 */
-		@XmlValue
-		public String value;
-
-		/**
-		 * Make a blank port description.
-		 */
-		public Port() {
-		}
-
-		/**
-		 * Make a port description suitable for the given input.
-		 * 
-		 * @param input
-		 */
-		public Port(Input input) {
-			name = input.getName();
-			if (input.getFile() != null) {
-				file = input.getFile();
-				value = "";
-			} else {
-				file = null;
-				value = input.getValue();
-			}
-			delimiter = input.getDelimiter();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java b/server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
deleted file mode 100644
index 1311272..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-/**
- * A convenient place to keep the names of URIs so that they can be got right
- * <i>once</i>.
- * 
- * @author Donal Fellows
- */
-public interface Namespaces {
-	/**
-	 * The XLink specification's namespace name.
-	 */
-	public static final String XLINK = "http://www.w3.org/1999/xlink";
-	/**
-	 * The XML Digital Signature specification's namespace name.
-	 */
-	public static final String XSIG = "http://www.w3.org/2000/09/xmldsig#";
-	/**
-	 * The Usage Record specification's namespace name.
-	 */
-	public static final String UR = "http://schema.ogf.org/urf/2003/09/urf";
-	/**
-	 * The T2flow document format's namespace name.
-	 */
-	public static final String T2FLOW = "http://taverna.sf.net/2008/xml/t2flow";
-	/**
-	 * The namespace for the server.
-	 */
-	public static final String SERVER = "http://ns.taverna.org.uk/2010/xml/server/";
-	public static final String SERVER_REST = SERVER + "rest/";
-	public static final String SERVER_SOAP = SERVER + "soap/";
-	public static final String FEED = SERVER + "feed/";
-	public static final String ADMIN = SERVER + "admin/";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Permission.java b/server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
deleted file mode 100644
index 258bfd0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlEnumValue;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Description of a permission to access a particular workflow run. Note that
- * users always have full access to their own runs, as does any user with the "
- * <tt>{@value org.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Permission")
-@XmlEnum
-public enum Permission {
-	/** Indicates that a user cannot see the workflow run at all. */
-	@XmlEnumValue("none")
-	None,
-	/**
-	 * Indicates that a user can see the workflow run and its contents, but
-	 * can't modify anything.
-	 */
-	@XmlEnumValue("read")
-	Read,
-	/**
-	 * Indicates that a user can update most aspects of a workflow, but cannot
-	 * work with either its security features or its lifetime.
-	 */
-	@XmlEnumValue("update")
-	Update,
-	/**
-	 * Indicates that a user can update almost all aspects of a workflow, with
-	 * only its security features being shrouded.
-	 */
-	@XmlEnumValue("destroy")
-	Destroy
-}
\ No newline at end of file


[15/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
new file mode 100644
index 0000000..399164d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaRun.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+
+/**
+ * The interface to a taverna workflow run, or "run" for short.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaRun extends Serializable {
+	/**
+	 * @return The identifier of the run.
+	 */
+	String getId();
+
+	/**
+	 * @return What was this run was create to execute.
+	 */
+	Workflow getWorkflow();
+
+	/**
+	 * @return The name of the run.
+	 */
+	String getName();
+
+	/**
+	 * @param name
+	 *            The new name of the run. May be truncated.
+	 */
+	void setName(String name);
+
+	/**
+	 * @return The name of the Baclava file to use for all inputs, or
+	 *         <tt>null</tt> if no Baclava file is set.
+	 */
+	String getInputBaclavaFile();
+
+	/**
+	 * Sets the Baclava file to use for all inputs. This overrides the use of
+	 * individual inputs.
+	 * 
+	 * @param filename
+	 *            The filename to use. Must not start with a <tt>/</tt> or
+	 *            contain any <tt>..</tt> segments. Will be interpreted relative
+	 *            to the run's working directory.
+	 * @throws FilesystemAccessException
+	 *             If the filename is invalid.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	void setInputBaclavaFile(String filename) throws FilesystemAccessException,
+			BadStateChangeException;
+
+	/**
+	 * @return The list of input assignments.
+	 */
+	List<Input> getInputs();
+
+	/**
+	 * Create an input assignment.
+	 * 
+	 * @param name
+	 *            The name of the port that this will be an input for.
+	 * @return The assignment reference.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	Input makeInput(String name) throws BadStateChangeException;
+
+	/**
+	 * @return The file (relative to the working directory) to write the outputs
+	 *         of the run to as a Baclava document, or <tt>null</tt> if they are
+	 *         to be written to non-Baclava files in a directory called
+	 *         <tt>out</tt>.
+	 */
+	String getOutputBaclavaFile();
+
+	/**
+	 * Sets where the output of the run is to be written to. This will cause the
+	 * output to be generated as a Baclava document, rather than a collection of
+	 * individual non-Baclava files in the subdirectory of the working directory
+	 * called <tt>out</tt>.
+	 * 
+	 * @param filename
+	 *            Where to write the Baclava file (or <tt>null</tt> to cause the
+	 *            output to be written to individual files); overwrites any
+	 *            previous setting of this value.
+	 * @throws FilesystemAccessException
+	 *             If the filename starts with a <tt>/</tt> or contains a
+	 *             <tt>..</tt> segment.
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 */
+	void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * @return When this run will expire, becoming eligible for automated
+	 *         deletion.
+	 */
+	Date getExpiry();
+
+	/**
+	 * Set when this run will expire.
+	 * 
+	 * @param d
+	 *            Expiry time. Deletion will happen some time after that.
+	 */
+	void setExpiry(Date d);
+
+	/**
+	 * @return The current status of the run.
+	 */
+	Status getStatus();
+
+	/**
+	 * Set the status of the run, which should cause it to move into the given
+	 * state. This may cause some significant changes.
+	 * 
+	 * @param s
+	 *            The state to try to change to.
+	 * @return <tt>null</tt>, or a string describing the incomplete state change
+	 *         if the operation has internally timed out.
+	 * @throws BadStateChangeException
+	 *             If the change to the given state is impossible.
+	 */
+	String setStatus(Status s) throws BadStateChangeException;
+
+	/**
+	 * @return Handle to the main working directory of the run.
+	 * @throws FilesystemAccessException
+	 */
+	Directory getWorkingDirectory() throws FilesystemAccessException;
+
+	/**
+	 * @return The list of listener instances attached to the run.
+	 */
+	List<Listener> getListeners();
+
+	/**
+	 * Add a listener to the run.
+	 * 
+	 * @param listener
+	 *            The listener to add.
+	 */
+	void addListener(Listener listener);
+
+	/**
+	 * @return The security context structure for this run.
+	 */
+	TavernaSecurityContext getSecurityContext();
+
+	/**
+	 * Kill off this run, removing all resources which it consumes.
+	 * 
+	 * @throws NoDestroyException
+	 *             If the destruction failed.
+	 */
+	void destroy() throws NoDestroyException;
+
+	/**
+	 * @return When this workflow run was created.
+	 */
+	Date getCreationTimestamp();
+
+	/**
+	 * @return When this workflow run was started, or <tt>null</tt> if it has
+	 *         never been started.
+	 */
+	Date getStartTimestamp();
+
+	/**
+	 * @return When this workflow run was found to have finished, or
+	 *         <tt>null</tt> if it has never finished (either still running or
+	 *         never started).
+	 */
+	Date getFinishTimestamp();
+
+	/**
+	 * Test if this run is really there.
+	 * 
+	 * <p>
+	 * <i>Implementation note:</i> Used to test communication fabrics, etc. so
+	 * implementations of this interface that do not delegate to another object
+	 * should do nothing.
+	 * 
+	 * @throws UnknownRunException
+	 *             If things fail.
+	 */
+	void ping() throws UnknownRunException;
+
+	/**
+	 * @return whether the run generates provenance data
+	 */
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param generateProvenance
+	 *            whether the run generates provenance data
+	 */
+	void setGenerateProvenance(boolean generateProvenance);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
new file mode 100644
index 0000000..b227bfa
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.xml.ws.handler.MessageContext;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Security context for a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaSecurityContext {
+	/**
+	 * @return Who owns the security context.
+	 */
+	UsernamePrincipal getOwner();
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may destroy the run or manipulate its
+	 * lifetime.
+	 * 
+	 * @return The names of the users who may use destroy operations. Read-only.
+	 */
+	Set<String> getPermittedDestroyers();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may destroy the run or manipulate its
+	 * lifetime.
+	 * 
+	 * @param destroyers
+	 *            The names of the users who may use destroy operations.
+	 */
+	void setPermittedDestroyers(Set<String> destroyers);
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may update the run (including writing to
+	 * files).
+	 * 
+	 * @return The names of the users who may use update operations. Read-only.
+	 */
+	Set<String> getPermittedUpdaters();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may update the run (including writing to
+	 * its files).
+	 * 
+	 * @param updaters
+	 *            The names of the users who may use update operations.
+	 */
+	void setPermittedUpdaters(Set<String> updaters);
+
+	/**
+	 * Describe the names of the users (as extracted from their
+	 * {@link Principal} objects) that may read from the run (including its
+	 * files).
+	 * 
+	 * @return The names of the users who may use read operations. Read-only.
+	 */
+	Set<String> getPermittedReaders();
+
+	/**
+	 * Sets the collection of names of users (as extracted from their
+	 * {@link Principal} objects) that may read from the run (including its
+	 * files).
+	 * 
+	 * @param readers
+	 *            The names of the users who may use read operations.
+	 */
+	void setPermittedReaders(Set<String> readers);
+
+	/**
+	 * @return The credentials owned by the user. Never <tt>null</tt>.
+	 */
+	Credential[] getCredentials();
+
+	/**
+	 * Add a credential to the owned set or replaces the old version with the
+	 * new one.
+	 * 
+	 * @param toAdd
+	 *            The credential to add.
+	 */
+	void addCredential(Credential toAdd);
+
+	/**
+	 * Remove a credential from the owned set. It's not a failure to remove
+	 * something that isn't in the set.
+	 * 
+	 * @param toDelete
+	 *            The credential to remove.
+	 */
+	void deleteCredential(Credential toDelete);
+
+	/**
+	 * Tests if the credential is valid. This includes testing whether the
+	 * underlying credential file exists and can be unlocked by the password in
+	 * the {@link Credential} object.
+	 * 
+	 * @param c
+	 *            The credential object to validate.
+	 * @throws InvalidCredentialException
+	 *             If it is invalid.
+	 */
+	void validateCredential(Credential c) throws InvalidCredentialException;
+
+	/**
+	 * @return The identities trusted by the user. Never <tt>null</tt>.
+	 */
+	Trust[] getTrusted();
+
+	/**
+	 * Add an identity to the trusted set.
+	 * 
+	 * @param toAdd
+	 *            The identity to add.
+	 */
+	void addTrusted(Trust toAdd);
+
+	/**
+	 * Remove an identity from the trusted set. It's not a failure to remove
+	 * something that isn't in the set.
+	 * 
+	 * @param toDelete
+	 *            The identity to remove.
+	 */
+	void deleteTrusted(Trust toDelete);
+
+	/**
+	 * Tests if the trusted identity descriptor is valid. This includes checking
+	 * whether the underlying trusted identity file exists.
+	 * 
+	 * @param t
+	 *            The trusted identity descriptor to check.
+	 * @throws InvalidCredentialException
+	 *             If it is invalid.
+	 */
+	void validateTrusted(Trust t) throws InvalidCredentialException;
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param securityContext
+	 *            The security context associated with the request that caused
+	 *            the workflow to be created.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception;
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param context
+	 *            The full information about the request that caused the
+	 *            workflow to be created.
+	 */
+	void initializeSecurityFromSOAPContext(MessageContext context);
+
+	/**
+	 * Establish the security context from how the owning workflow run was
+	 * created. In particular, this gives an opportunity for boot-strapping
+	 * things with any delegateable credentials.
+	 * 
+	 * @param headers
+	 *            The full information about the request that caused the
+	 *            workflow to be created.
+	 */
+	void initializeSecurityFromRESTContext(HttpHeaders headers);
+
+	/**
+	 * Transfer the security context to the remote system.
+	 * 
+	 * @throws IOException
+	 *             If the communication fails.
+	 * @throws GeneralSecurityException
+	 *             If the assembly of the context fails.
+	 * @throws ImplementationException
+	 *             If the local worker has problems with creating the realized
+	 *             security context.
+	 */
+	void conveySecurity() throws GeneralSecurityException, IOException,
+			ImplementationException;
+
+	/**
+	 * @return The factory that created this security context.
+	 */
+	SecurityContextFactory getFactory();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
new file mode 100644
index 0000000..e5cd02c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.interfaces;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+
+/**
+ * How to manufacture URIs to workflow runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface UriBuilderFactory {
+	/**
+	 * Given a run, get a factory for RESTful URIs to resources associated
+	 * with it.
+	 * 
+	 * @param run
+	 *            The run in question.
+	 * @return The {@link URI} factory.
+	 */
+	UriBuilder getRunUriBuilder(TavernaRun run);
+
+	/**
+	 * @return a URI factory that is preconfigured to point to the base of
+	 *         the webapp.
+	 */
+	UriBuilder getBaseUriBuilder();
+
+	/**
+	 * Resolves a URI with respect to the base URI of the factory.
+	 * 
+	 * @param uri
+	 *            The URI to resolve, or <tt>null</tt>.
+	 * @return The resolved URI, or <tt>null</tt> if <b>uri</b> is
+	 *         <tt>null</tt>.
+	 */
+	String resolve(String uri);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
new file mode 100644
index 0000000..cfbbe79
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Interfaces to the main worker classes that provide the magical power
+ * that drives the webapp front-end.
+ */
+package org.taverna.server.master.interfaces;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
new file mode 100644
index 0000000..fc7f881
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import static java.lang.System.getSecurityManager;
+import static java.lang.System.setProperty;
+import static java.lang.System.setSecurityManager;
+import static java.rmi.registry.LocateRegistry.createRegistry;
+import static java.rmi.registry.LocateRegistry.getRegistry;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.URI;
+import java.net.URL;
+import java.rmi.MarshalledObject;
+import java.rmi.RMISecurityManager;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.Resource;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.factories.RunFactory;
+import org.taverna.server.master.interaction.InteractionFeedSupport;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.notification.atom.EventDAO;
+import org.taverna.server.master.usage.UsageRecordRecorder;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.worker.FactoryBean;
+import org.taverna.server.master.worker.RemoteRunDelegate;
+import org.taverna.server.master.worker.RunFactoryConfiguration;
+
+import uk.org.taverna.scufl2.api.io.WriterException;
+
+/**
+ * Bridge to remote runs via RMI.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs")
+public abstract class AbstractRemoteRunFactory extends RunFactoryConfiguration
+		implements ListenerFactory, RunFactory, FactoryBean {
+	/**
+	 * Whether to apply stronger limitations than normal to RMI. It is
+	 * recommended that this be true!
+	 */
+	@Value("${rmi.localhostOnly}")
+	private boolean rmiLocalhostOnly;
+	/** The interaction host name. */
+	private String interhost;
+	/** The interaction port number. */
+	private String interport;
+	private Process registryProcess;
+	/**
+	 * The interaction WebDAV location. Will be resolved before being passed to
+	 * the back-end.
+	 */
+	private String interwebdav;
+	/**
+	 * The interaction ATOM feed location. Will be resolved before being passed
+	 * to the back-end.
+	 */
+	private String interfeed;
+	/** Used for doing URI resolution. */
+	@Resource(name = "webapp")
+	private UriBuilderFactory baseurifactory;
+	@Autowired
+	private InteractionFeedSupport interactionFeedSupport;
+
+	@Value("${taverna.interaction.host}")
+	void setInteractionHost(String host) {
+		if (host != null && host.equals("none"))
+			host = null;
+		interhost = host;
+	}
+
+	@Value("${taverna.interaction.port}")
+	void setInteractionPort(String port) {
+		if (port != null && port.equals("none"))
+			port = null;
+		interport = port;
+	}
+
+	@Value("${taverna.interaction.webdav_path}")
+	void setInteractionWebdav(String webdav) {
+		if (webdav != null && webdav.equals("none"))
+			webdav = null;
+		interwebdav = webdav;
+	}
+
+	@Value("${taverna.interaction.feed_path}")
+	void setInteractionFeed(String feed) {
+		if (feed != null && feed.equals("none"))
+			feed = null;
+		interfeed = feed;
+	}
+
+	@Override
+	protected void reinitRegistry() {
+		registry = null;
+		if (registryProcess != null) {
+			registryProcess.destroy();
+			registryProcess = null;
+		}
+	}
+
+	protected void initInteractionDetails(RemoteRunFactory factory)
+			throws RemoteException {
+		if (interhost != null) {
+			String feed = baseurifactory.resolve(interfeed);
+			String webdav = baseurifactory.resolve(interwebdav);
+			factory.setInteractionServiceDetails(interhost, interport, webdav,
+					feed);
+		}
+	}
+
+	protected static final Process launchSubprocess(ProcessBuilder b)
+			throws IOException {
+		Thread t = Thread.currentThread();
+		ClassLoader ccl = t.getContextClassLoader();
+		try {
+			t.setContextClassLoader(null);
+			return b.start();
+		} finally {
+			t.setContextClassLoader(ccl);
+		}
+	}
+
+	/** Get a handle to a new instance of the RMI registry. */
+	private Registry makeRegistry(int port) throws RemoteException {
+		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
+		p.command().add("-jar");
+		p.command().add(getRmiRegistryJar());
+		p.command().add(Integer.toString(port));
+		p.command().add(Boolean.toString(rmiLocalhostOnly));
+		try {
+			Process proc = launchSubprocess(p);
+			Thread.sleep(getSleepTime());
+			try {
+				if (proc.exitValue() == 0)
+					return null;
+				String error = IOUtils.toString(proc.getErrorStream());
+				throw new RemoteException(error);
+			} catch (IllegalThreadStateException ise) {
+				// Still running!
+			}
+			try (ObjectInputStream ois = new ObjectInputStream(
+					proc.getInputStream())) {
+				@SuppressWarnings("unchecked")
+				Registry r = ((MarshalledObject<Registry>) ois.readObject())
+						.get();
+				registryProcess = proc;
+				return r;
+			}
+		} catch (RemoteException e) {
+			throw e;
+		} catch (ClassNotFoundException e) {
+			throw new RemoteException("unexpected registry type", e);
+		} catch (IOException e) {
+			throw new RemoteException("unexpected IO problem with registry", e);
+		} catch (InterruptedException e) {
+			throw new RemoteException("unexpected interrupt");
+		}
+	}
+
+	/**
+	 * @return A handle to the current RMI registry.
+	 */
+	protected Registry getTheRegistry() {
+		try {
+			if (registry != null) {
+				registry.list();
+				return registry;
+			}
+		} catch (RemoteException e) {
+			log.warn("non-functioning existing registry handle", e);
+			registry = null;
+		}
+		try {
+			registry = getRegistry(getRegistryHost(), getRegistryPort());
+			registry.list();
+			return registry;
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle.");
+			registry = null;
+			log.warn("Will build new registry, "
+					+ "but service restart ability is at risk.");
+			try {
+				registry = makeRegistry(getRegistryPort());
+				registry.list();
+				return registry;
+			} catch (RemoteException e2) {
+				log.error(
+						"failed to create local working RMI registry on port "
+								+ getRegistryPort(), e2);
+				log.info("original connection exception", e);
+			}
+		}
+		try {
+			registry = getRegistry(getRegistryHost(), REGISTRY_PORT);
+			registry.list();
+			return registry;
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle on backup port.");
+			try {
+				registry = makeRegistry(REGISTRY_PORT);
+				registry.list();
+				return registry;
+			} catch (RemoteException e2) {
+				log.fatal(
+						"totally failed to get registry handle, even on fallback!",
+						e2);
+				log.info("original connection exception", e);
+				registry = null;
+				throw new RuntimeException("No RMI Registry Available");
+			}
+		}
+	}
+
+	private Registry registry;
+	/**
+	 * The name of the resource that describes the default security policy to
+	 * install.
+	 */
+	public static final String SECURITY_POLICY_FILE = "security.policy";
+	private SecurityContextFactory securityFactory;
+	UsageRecordRecorder usageRecordSink;
+	private EventDAO masterEventFeed;
+
+	@Autowired(required = true)
+	void setSecurityContextFactory(SecurityContextFactory factory) {
+		this.securityFactory = factory;
+	}
+
+	@Autowired(required = true)
+	void setMasterEventFeed(EventDAO masterEventFeed) {
+		this.masterEventFeed = masterEventFeed;
+	}
+
+	@Autowired(required = true)
+	void setUsageRecordSink(UsageRecordRecorder usageRecordSink) {
+		this.usageRecordSink = usageRecordSink;
+	}
+
+	/**
+	 * Configures the Java security model. Not currently used, as it is
+	 * viciously difficult to get right!
+	 */
+	@SuppressWarnings("unused")
+	private static void installSecurityManager() {
+		if (getSecurityManager() == null) {
+			setProperty("java.security.policy", AbstractRemoteRunFactory.class
+					.getClassLoader().getResource(SECURITY_POLICY_FILE)
+					.toExternalForm());
+			setSecurityManager(new RMISecurityManager());
+		}
+	}
+
+	// static {
+	// installSecurityManager();
+	// }
+
+	/**
+	 * Set up the run expiry management engine.
+	 * 
+	 * @throws JAXBException
+	 */
+	public AbstractRemoteRunFactory() throws JAXBException {
+		try {
+			registry = LocateRegistry.getRegistry();
+			registry.list();
+		} catch (RemoteException e) {
+			log.warn("Failed to get working RMI registry handle.");
+			log.warn("Will build new registry, but service restart ability is at risk.");
+			try {
+				registry = createRegistry(REGISTRY_PORT);
+				registry.list();
+			} catch (RemoteException e2) {
+				log.error("failed to create working RMI registry", e2);
+				log.info("original connection exception", e);
+			}
+		}
+	}
+
+	@Override
+	public List<String> getSupportedListenerTypes() {
+		try {
+			RemoteRunDelegate rrd = runDB.pickArbitraryRun();
+			if (rrd != null)
+				return rrd.getListenerTypes();
+			log.warn("no remote runs; no listener types");
+		} catch (Exception e) {
+			log.warn("failed to get list of listener types", e);
+		}
+		return new ArrayList<>();
+	}
+
+	@Override
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException {
+		if (run instanceof RemoteRunDelegate)
+			return ((RemoteRunDelegate) run).makeListener(listenerType,
+					configuration);
+		throw new NoListenerException("unexpected run type: " + run.getClass());
+	}
+
+	@Override
+	public TavernaRun create(UsernamePrincipal creator, Workflow workflow)
+			throws NoCreateException {
+		try {
+			Date now = new Date();
+			UUID id = randomUUID();
+			RemoteSingleRun rsr = getRealRun(creator, workflow, id);
+			RemoteRunDelegate run = new RemoteRunDelegate(now, workflow, rsr,
+					state.getDefaultLifetime(), runDB, id,
+					state.getGenerateProvenance(), this);
+			run.setSecurityContext(securityFactory.create(run, creator));
+			@Nonnull
+			URI feed = interactionFeedSupport.getFeedURI(run);
+			@Nonnull
+			URL feedUrl = feed.toURL();
+			@Nonnull
+			URL webdavUrl = baseurifactory.getRunUriBuilder(run)
+					.path(DIR + "/interactions").build().toURL();
+			@Nullable
+			URL pub = interactionFeedSupport.getLocalFeedBase(feed);
+			rsr.setInteractionServiceDetails(feedUrl, webdavUrl, pub);
+			return run;
+		} catch (NoCreateException e) {
+			log.warn("failed to build run instance", e);
+			throw e;
+		} catch (Exception e) {
+			log.warn("failed to build run instance", e);
+			throw new NoCreateException("failed to build run instance", e);
+		}
+	}
+
+	/**
+	 * Gets the RMI connector for a new run.
+	 * 
+	 * @param creator
+	 *            Who is creating the workflow run.
+	 * @param workflow
+	 *            What workflow are they instantiating.
+	 * @param id
+	 *            The identity token for the run, newly minted.
+	 * @return The remote interface to the run.
+	 * @throws Exception
+	 *             Just about anything can go wrong...
+	 */
+	protected abstract RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception;
+
+	/**
+	 * How to convert a wrapped workflow into XML.
+	 * 
+	 * @param workflow
+	 *            The wrapped workflow.
+	 * @return The XML version of the document.
+	 * @throws JAXBException
+	 *             If serialization fails.
+	 */
+	protected byte[] serializeWorkflow(Workflow workflow) throws JAXBException {
+		try {
+			return workflow.getScufl2Bytes();
+		} catch (IOException e) {
+			throw new JAXBException("problem converting to scufl2", e);
+		} catch (WriterException e) {
+			throw new JAXBException("problem converting to scufl2", e);
+		}
+	}
+
+	private void acceptUsageRecord(String usageRecord) {
+		if (usageRecordSink != null)
+			usageRecordSink.storeUsageRecord(usageRecord);
+		runDB.checkForFinishNow();
+	}
+
+	/**
+	 * Make a Remote object that can act as a consumer for usage records.
+	 * 
+	 * @param creator
+	 * 
+	 * @return The receiver, or <tt>null</tt> if the construction fails.
+	 */
+	protected UsageRecordReceiver makeURReciver(UsernamePrincipal creator) {
+		try {
+			@SuppressWarnings("serial")
+			class URReceiver extends UnicastRemoteObject implements
+					UsageRecordReceiver {
+				public URReceiver() throws RemoteException {
+					super();
+				}
+
+				@Override
+				public void acceptUsageRecord(String usageRecord) {
+					AbstractRemoteRunFactory.this.acceptUsageRecord(usageRecord);
+				}
+			}
+			return new URReceiver();
+		} catch (RemoteException e) {
+			log.warn("failed to build usage record receiver", e);
+			return null;
+		}
+	}
+
+	@Override
+	public EventDAO getMasterEventFeed() {
+		return masterEventFeed;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
new file mode 100644
index 0000000..b67e121
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import static java.lang.System.getProperty;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+import static java.util.Calendar.SECOND;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+
+import java.io.File;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.Calendar;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A simple factory for workflow runs that forks runs from a subprocess.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for simple singleton forked run.")
+public class ForkRunFactory extends AbstractRemoteRunFactory implements
+		ConfigurableRunFactory {
+	private int lastStartupCheckCount;
+	private Integer lastExitCode;
+	private RemoteRunFactory factory;
+	private Process factoryProcess;
+	private String factoryProcessName;
+
+	/**
+	 * Create a factory for remote runs that works by forking off a subprocess.
+	 * 
+	 * @throws JAXBException
+	 *             Shouldn't happen.
+	 */
+	public ForkRunFactory() throws JAXBException {
+	}
+
+	@PostConstruct
+	protected void initRegistry() {
+		log.info("waiting for availability of default RMI registry");
+		getTheRegistry();
+	}
+
+	@Override
+	protected void reinitFactory() {
+		boolean makeFactory = factory != null;
+		killFactory();
+		try {
+			if (makeFactory)
+				initFactory();
+		} catch (Exception e) {
+			log.fatal("failed to make connection to remote run factory", e);
+		}
+	}
+
+	private RemoteRunFactory getFactory() throws RemoteException {
+		try {
+			initFactory();
+		} catch (RemoteException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new RemoteException("problem constructing factory", e);
+		}
+		return factory;
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	@Override
+	public int getLastStartupCheckCount() {
+		return lastStartupCheckCount;
+	}
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	@Override
+	public Integer getLastExitCode() {
+		return lastExitCode;
+	}
+
+	/**
+	 * @return What the factory subprocess's main RMI interface is registered
+	 *         as.
+	 */
+	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
+	@Override
+	public String getFactoryProcessName() {
+		return factoryProcessName;
+	}
+
+	/**
+	 * Makes the subprocess that manufactures runs.
+	 * 
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	public void initFactory() throws Exception {
+		if (factory != null)
+			return;
+		// Generate the arguments to use when spawning the subprocess
+		factoryProcessName = state.getFactoryProcessNamePrefix() + randomUUID();
+		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
+		p.command().add("-jar");
+		p.command().add(getServerWorkerJar());
+		if (getExecuteWorkflowScript() == null)
+			log.fatal("no execute workflow script");
+		p.command().add(getExecuteWorkflowScript());
+		p.command().addAll(asList(getExtraArguments()));
+		p.command().add(factoryProcessName);
+		p.redirectErrorStream(true);
+		p.directory(new File(getProperty("javax.servlet.context.tempdir",
+				getProperty("java.io.tmpdir"))));
+
+		// Spawn the subprocess
+		log.info("about to create subprocess: " + p.command());
+		
+		factoryProcess = launchSubprocess(p);
+		outlog = new StreamLogger("FactoryStdout", factoryProcess.getInputStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+		errlog = new StreamLogger("FactoryStderr", factoryProcess.getErrorStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+
+		// Wait for the subprocess to register itself in the RMI registry
+		Calendar deadline = Calendar.getInstance();
+		deadline.add(SECOND, state.getWaitSeconds());
+		Exception lastException = null;
+		lastStartupCheckCount = 0;
+		while (deadline.after(Calendar.getInstance())) {
+			try {
+				sleep(state.getSleepMS());
+				lastStartupCheckCount++;
+				factory = getRemoteFactoryHandle(factoryProcessName);
+				initInteractionDetails(factory);
+				return;
+			} catch (InterruptedException ie) {
+				continue;
+			} catch (NotBoundException nbe) {
+				lastException = nbe;
+				log.info("resource \"" + factoryProcessName
+						+ "\" not yet registered...");
+				continue;
+			} catch (RemoteException re) {
+				// Unpack a remote exception if we can
+				lastException = re;
+				try {
+					if (re.getCause() != null)
+						lastException = (Exception) re.getCause();
+				} catch (Throwable t) {
+					// Ignore!
+				}
+			} catch (RuntimeException e) {
+				lastException = e;
+			}
+		}
+		if (lastException == null)
+			lastException = new InterruptedException();
+		throw lastException;
+	}
+
+	private StreamLogger outlog, errlog;
+
+	private void stopLoggers() {
+		if (outlog != null)
+			outlog.stop();
+		outlog = null;
+		if (errlog != null)
+			errlog.stop();
+		errlog = null;
+	}
+
+	private RemoteRunFactory getRemoteFactoryHandle(String name)
+			throws RemoteException, NotBoundException {
+		log.info("about to look up resource called " + name);
+		try {
+			// Validate registry connection first
+			getTheRegistry().list();
+		} catch (ConnectException | ConnectIOException e) {
+			log.warn("connection problems with registry", e);
+		}
+		RemoteRunFactory rrf = (RemoteRunFactory) getTheRegistry().lookup(name);
+		log.info("successfully connected to factory subprocess "
+				+ factoryProcessName);
+		return rrf;
+	}
+
+	/**
+	 * Destroys the subprocess that manufactures runs.
+	 */
+	@PreDestroy
+	public void killFactory() {
+		if (factory != null) {
+			log.info("requesting shutdown of " + factoryProcessName);
+			try {
+				factory.shutdown();
+				sleep(700);
+			} catch (RemoteException e) {
+				log.warn(factoryProcessName + " failed to shut down nicely", e);
+			} catch (InterruptedException e) {
+				if (log.isDebugEnabled())
+					log.debug("interrupted during wait after asking "
+							+ factoryProcessName + " to shut down", e);
+			} finally {
+				factory = null;
+			}
+		}
+
+		if (factoryProcess != null) {
+			int code = -1;
+			try {
+				lastExitCode = code = factoryProcess.exitValue();
+				log.info(factoryProcessName + " already dead?");
+			} catch (RuntimeException e) {
+				log.info("trying to force death of " + factoryProcessName);
+				try {
+					factoryProcess.destroy();
+					sleep(350); // takes a little time, even normally
+					lastExitCode = code = factoryProcess.exitValue();
+				} catch (Exception e2) {
+					code = -1;
+				}
+			} finally {
+				factoryProcess = null;
+				stopLoggers();
+			}
+			if (code > 128) {
+				log.info(factoryProcessName + " died with signal="
+						+ (code - 128));
+			} else if (code >= 0) {
+				log.info(factoryProcessName + " process killed: code=" + code);
+			} else {
+				log.warn(factoryProcessName + " not yet dead");
+			}
+		}
+	}
+
+	/**
+	 * The real core of the run builder, factored out from its reliability
+	 * support.
+	 * 
+	 * @param creator
+	 *            Who created this workflow?
+	 * @param wf
+	 *            The serialized workflow.
+	 * @return The remote handle of the workflow run.
+	 * @throws RemoteException
+	 *             If anything fails (communications error, etc.)
+	 */
+	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
+			@Nonnull byte[] wf, UUID id) throws RemoteException {
+		@Nonnull
+		String globaluser = "Unknown Person";
+		if (creator != null)
+			globaluser = creator.getName();
+		RemoteSingleRun rsr = getFactory().make(wf, globaluser,
+				makeURReciver(creator), id);
+		incrementRunCount();
+		return rsr;
+	}
+
+	@Override
+	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception {
+		@Nonnull
+		byte[] wf = serializeWorkflow(workflow);
+		for (int i = 0; i < 3; i++) {
+			initFactory();
+			try {
+				return getRealRun(creator, wf, id);
+			} catch (ConnectException | ConnectIOException e) {
+				// factory was lost; try to recreate
+			}
+			killFactory();
+		}
+		throw new NoCreateException("total failure to connect to factory "
+				+ factoryProcessName + "despite attempting restart");
+	}
+
+	@Override
+	public String[] getFactoryProcessMapping() {
+		return new String[0];
+	}
+
+	@Override
+	protected int operatingCount() throws Exception {
+		return getFactory().countOperatingRuns();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
new file mode 100644
index 0000000..e449373
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import static java.lang.System.getProperty;
+import static java.lang.Thread.sleep;
+import static java.util.Arrays.asList;
+import static java.util.Calendar.SECOND;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+import static org.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.localworker.remote.RemoteRunFactory;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.interfaces.LocalIdentityMapper;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A simple factory for workflow runs that forks runs from a subprocess.
+ * 
+ * @author Donal Fellows
+ */
+@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for a user-specific forked run.")
+public class IdAwareForkRunFactory extends AbstractRemoteRunFactory implements
+		ConfigurableRunFactory {
+	private MetaFactory forker;
+	private Map<String, RemoteRunFactory> factory;
+	private Map<String, String> factoryProcessName;
+
+	/**
+	 * Create a factory for remote runs that works by forking off a subprocess.
+	 * 
+	 * @throws JAXBException
+	 *             Shouldn't happen.
+	 */
+	public IdAwareForkRunFactory() throws JAXBException {
+		factory = new HashMap<>();
+		factoryProcessName = new HashMap<>();
+	}
+
+	@Override
+	protected void reinitFactory() {
+		boolean makeForker = forker != null;
+		try {
+			killForker();
+		} catch (Exception e) {
+			log.warn("exception when killing secure-fork process", e);
+		}
+		try {
+			if (makeForker)
+				initMetaFactory();
+		} catch (Exception e) {
+			log.fatal("failed to make secure-fork process", e);
+		}
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	public int getLastStartupCheckCount() {
+		return forker == null ? 0 : forker.lastStartupCheckCount();
+	}
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@Override
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	public Integer getLastExitCode() {
+		return forker == null ? null : forker.lastExitCode();
+	}
+
+	/**
+	 * @return The mapping of user names to RMI factory IDs.
+	 */
+	@Override
+	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
+	public String[] getFactoryProcessMapping() {
+		ArrayList<String> result = new ArrayList<>();
+		ArrayList<String> keys = new ArrayList<>(factoryProcessName.keySet());
+		String[] ks = keys.toArray(new String[keys.size()]);
+		Arrays.sort(ks);
+		for (String k : ks) {
+			result.add(k);
+			result.add(factoryProcessName.get(k));
+		}
+		return result.toArray(new String[result.size()]);
+	}
+
+	/**
+	 * How construction of factories is actually done.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public interface MetaFactory {
+		/**
+		 * Make a factory for the given user.
+		 * 
+		 * @param username
+		 *            Who to make it for.
+		 * @return Handle of the factory.
+		 * @throws Exception
+		 *             If anything goes wrong.
+		 */
+		RemoteRunFactory make(String username) throws Exception;
+
+		/**
+		 * Shut down the meta-factory. It is not defined whether factories
+		 * created by it are also shut down at the same time.
+		 * 
+		 * @throws IOException
+		 *             If something goes wrong when communicating with the
+		 *             meta-factory.
+		 * @throws InterruptedException
+		 *             If something stops us waiting for the shut down to
+		 *             happen.
+		 */
+		void close() throws IOException, InterruptedException;
+
+		int lastStartupCheckCount();
+
+		Integer lastExitCode();
+	}
+
+	void registerFactory(String username, String fpn, RemoteRunFactory f) {
+		factoryProcessName.put(username, fpn);
+		factory.put(username, f);
+	}
+
+	/**
+	 * Makes the connection to the meta-factory that makes factories.
+	 * 
+	 * @throws IOException
+	 *             If the connection fails.
+	 */
+	@PostConstruct
+	void initMetaFactory() throws IOException {
+		log.info("waiting for availability of default RMI registry");
+		getTheRegistry();
+		log.info("constructing secure fork subprocess");
+		forker = new SecureFork(this, state, log);
+	}
+
+	private void killForker() throws IOException, InterruptedException {
+		try {
+			if (forker != null)
+				forker.close();
+		} finally {
+			forker = null;
+		}
+	}
+
+	/**
+	 * Makes the subprocess that manufactures runs.
+	 * 
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	private void initFactory(String username) throws Exception {
+		if (factory.containsKey(username))
+			return;
+		if (forker == null)
+			initMetaFactory();
+		forker.make(username);
+	}
+
+	/**
+	 * Destroys the subprocess that manufactures runs.
+	 */
+	@PreDestroy
+	public void killFactories() {
+		if (!factory.isEmpty()) {
+			Iterator<String> keys = factory.keySet().iterator();
+			while (keys.hasNext()) {
+				String key = keys.next();
+				log.info("requesting shutdown of "
+						+ factoryProcessName.get(key));
+				try {
+					factory.get(key).shutdown();
+				} catch (RemoteException e) {
+					log.warn(factoryProcessName.get(key)
+							+ " failed to shut down nicely", e);
+				} finally {
+					keys.remove();
+					factoryProcessName.remove(key);
+				}
+			}
+			try {
+				sleep(700);
+			} catch (InterruptedException e) {
+				if (log.isDebugEnabled())
+					log.debug("interrupted during wait after "
+							+ "asking factories to shut down", e);
+			}
+		}
+
+		try {
+			killForker();
+		} catch (Exception e) {
+			if (log.isDebugEnabled())
+				log.debug("exception in shutdown of secure-fork process", e);
+		}
+	}
+
+	@Override
+	protected void finalize() throws Throwable {
+		killFactories();
+		super.finalize();
+	}
+
+	@Autowired
+	public void setIdMapper(LocalIdentityMapper mapper) {
+		this.mapper = mapper;
+	}
+
+	private LocalIdentityMapper mapper;
+
+	/**
+	 * The real core of the run builder, factored out from its reliability
+	 * support.
+	 * 
+	 * @param creator
+	 *            Who created this workflow?
+	 * @param username
+	 *            What user account is this workflow to be executed in?
+	 * @param wf
+	 *            The serialized workflow.
+	 * @return The remote handle of the workflow run.
+	 * @throws RemoteException
+	 *             If anything fails (communications error, etc.)
+	 */
+	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
+			@Nonnull String username, @Nonnull byte[] wf, UUID id)
+			throws RemoteException {
+		String globaluser = "Unknown Person";
+		if (creator != null)
+			globaluser = creator.getName();
+		RemoteSingleRun rsr = factory.get(username).make(wf, globaluser,
+				makeURReciver(creator), id);
+		incrementRunCount();
+		return rsr;
+	}
+
+	@Override
+	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
+			Workflow workflow, UUID id) throws Exception {
+		byte[] wf = serializeWorkflow(workflow);
+		String username = mapper == null ? null : mapper
+				.getUsernameForPrincipal(creator);
+		if (username == null)
+			throw new Exception("cannot determine who to run workflow as; "
+					+ "local identity mapper returned null");
+		for (int i = 0; i < 3; i++) {
+			if (!factory.containsKey(username))
+				initFactory(username);
+			try {
+				return getRealRun(creator, username, wf, id);
+			} catch (ConnectException | ConnectIOException e) {
+				// factory was lost; try to recreate
+			}
+			factory.remove(username);
+		}
+		throw new NoCreateException("total failure to connect to factory "
+				+ factoryProcessName + "despite attempting restart");
+	}
+
+	@Value("${secureForkPasswordFile}")
+	@Order(20)
+	public void setPasswordSource(String passwordSource) {
+		if (passwordSource == null || passwordSource.isEmpty()
+				|| passwordSource.startsWith("${"))
+			state.setDefaultPasswordFile(null);
+		else
+			state.setDefaultPasswordFile(passwordSource);
+		if (state.getPasswordFile() == null)
+			log.info("assuming password-free forking enabled");
+		else
+			log.info("configured secureForkPasswordFile from context as "
+					+ state.getPasswordFile());
+	}
+
+	@Override
+	public String getFactoryProcessName() {
+		return "<PROPERTY-NOT-SUPPORTED>";
+	}
+
+	@Override
+	protected int operatingCount() throws Exception {
+		int total = 0;
+		for (RemoteRunFactory rrf : factory.values())
+			total += rrf.countOperatingRuns();
+		return total;
+	}
+}
+
+/**
+ * The connector that handles the secure fork process itself.
+ * 
+ * @author Donal Fellows
+ */
+class SecureFork implements IdAwareForkRunFactory.MetaFactory {
+	private IdAwareForkRunFactory main;
+	private Process process;
+	private PrintWriter channel;
+	private int lastStartupCheckCount;
+	private Integer lastExitCode;
+	private Log log;
+	private LocalWorkerState state;
+	private StreamLogger out, err;
+
+	/**
+	 * Construct the command to run the meta-factory process.
+	 * 
+	 * @param args
+	 *            The live list of arguments to pass.
+	 */
+	public void initFactoryArgs(List<String> args) {
+		args.add(main.getJavaBinary());
+		String pwf = main.getPasswordFile();
+		if (pwf != null) {
+			args.add("-Dpassword.file=" + pwf);
+		}
+		args.add("-jar");
+		args.add(main.getServerForkerJar());
+		args.add(main.getJavaBinary());
+		args.add("-jar");
+		args.add(main.getServerWorkerJar());
+		if (main.getExecuteWorkflowScript() == null)
+			log.fatal("no execute workflow script");
+		args.add(main.getExecuteWorkflowScript());
+		args.addAll(asList(main.getExtraArguments()));
+	}
+
+	SecureFork(IdAwareForkRunFactory main, LocalWorkerState state, Log log)
+			throws IOException {
+		this.main = main;
+		this.log = log;
+		this.state = state;
+		ProcessBuilder p = new ProcessBuilder();
+		initFactoryArgs(p.command());
+		p.redirectErrorStream(true);
+		p.directory(new File(getProperty("javax.servlet.context.tempdir",
+				getProperty("java.io.tmpdir"))));
+
+		// Spawn the subprocess
+		log.info("about to create subprocess: " + p.command());
+		log.info("subprocess directory: " + p.directory());
+		process = launchSubprocess(p);
+		channel = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
+				process.getOutputStream())), true);
+		// Log the responses
+		out = new StreamLogger("ForkedStdout", process.getInputStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+		err = new StreamLogger("ForkedStderr", process.getErrorStream()) {
+			@Override
+			protected void write(String msg) {
+				log.info(msg);
+			}
+		};
+	}
+
+	@Override
+	public void close() throws IOException, InterruptedException {
+		try {
+			if (process != null) {
+				log.info("about to close down subprocess");
+				channel.close();
+				int code = -1;
+				try {
+					try {
+						code = process.exitValue();
+						log.info("secure-fork process already dead?");
+					} catch (IllegalThreadStateException e) {
+						try {
+							code = process.waitFor();
+						} catch (InterruptedException e1) {
+							log.info("interrupted waiting for natural death of secure-fork process?!");
+							process.destroy();
+							code = process.waitFor();
+						}
+					}
+				} finally {
+					lastExitCode = code;
+					if (code > 128) {
+						log.info("secure-fork process died with signal="
+								+ (code - 128));
+					} else if (code >= 0) {
+						log.info("secure-fork process killed: code=" + code);
+					} else {
+						log.warn("secure-fork process not yet dead");
+					}
+				}
+			}
+		} finally {
+			process = null;
+			channel = null;
+			out.stop();
+			err.stop();
+		}
+	}
+
+	protected void make(String username, String fpn) {
+		log.info("about to request subprocess creation for " + username
+				+ " producing ID " + fpn);
+		channel.println(username + " " + fpn);
+	}
+
+	@Override
+	public RemoteRunFactory make(String username) throws Exception {
+		try {
+			main.getTheRegistry().list(); // Validate registry connection first
+		} catch (ConnectException | ConnectIOException e) {
+			log.warn("connection problems with registry", e);
+		} catch (RemoteException e) {
+			if (e.getCause() != null && e.getCause() instanceof Exception) {
+				throw (Exception) e.getCause();
+			}
+			log.warn("connection problems with registry", e);
+		}
+
+		String fpn = state.getFactoryProcessNamePrefix() + randomUUID();
+		make(username, fpn);
+
+		// Wait for the subprocess to register itself in the RMI registry
+		Calendar deadline = Calendar.getInstance();
+		deadline.add(SECOND, state.getWaitSeconds());
+		Exception lastException = null;
+		lastStartupCheckCount = 0;
+		while (deadline.after(Calendar.getInstance())) {
+			try {
+				sleep(state.getSleepMS());
+				lastStartupCheckCount++;
+				log.info("about to look up resource called " + fpn);
+				RemoteRunFactory f = (RemoteRunFactory) main.getTheRegistry()
+						.lookup(fpn);
+				log.info("successfully connected to factory subprocess " + fpn);
+				main.initInteractionDetails(f);
+				main.registerFactory(username, fpn, f);
+				return f;
+			} catch (InterruptedException ie) {
+				continue;
+			} catch (NotBoundException nbe) {
+				lastException = nbe;
+				log.info("resource \"" + fpn + "\" not yet registered...");
+				continue;
+			} catch (RemoteException re) {
+				// Unpack a remote exception if we can
+				lastException = re;
+				try {
+					if (re.getCause() != null)
+						lastException = (Exception) re.getCause();
+				} catch (Throwable t) {
+					// Ignore!
+				}
+			} catch (Exception e) {
+				lastException = e;
+			}
+		}
+		if (lastException == null)
+			lastException = new InterruptedException();
+		throw lastException;
+	}
+
+	@Override
+	public Integer lastExitCode() {
+		return lastExitCode;
+	}
+
+	@Override
+	public int lastStartupCheckCount() {
+		return lastStartupCheckCount;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
new file mode 100644
index 0000000..f890204
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Provider of the configuration of the "localworker.factory" bean, which is
+ * sufficiently complex to be too hard to manufacture directly from the XML
+ * configuration.
+ * 
+ * @author Donal Fellows
+ */
+@Configuration
+public class LocalWorkerFactory {
+	@Bean(name = "localworker.factory")
+	AbstractRemoteRunFactory getLocalworkerFactory(
+			@Value("${backEndFactory}") String mode) throws Exception {
+		if (mode == null || mode.isEmpty() || mode.startsWith("${"))
+			throw new Exception("no value for ${backEndFactory}");
+		Class<?> c = Class.forName(mode);
+		if (AbstractRemoteRunFactory.class.isAssignableFrom(c))
+			return (AbstractRemoteRunFactory) c.newInstance();
+		throw new Exception("unknown remote run factory: " + mode);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
new file mode 100644
index 0000000..9f0f39b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import static java.io.File.separator;
+import static java.lang.System.getProperty;
+import static java.rmi.registry.Registry.REGISTRY_PORT;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
+import static org.taverna.server.master.defaults.Default.PASSWORD_FILE;
+import static org.taverna.server.master.defaults.Default.REGISTRY_JAR;
+import static org.taverna.server.master.defaults.Default.RMI_PREFIX;
+import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
+import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
+import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
+import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
+import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
+import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
+import static org.taverna.server.master.localworker.PersistedState.KEY;
+import static org.taverna.server.master.localworker.PersistedState.makeInstance;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URI;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.defaults.Default;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The persistent state of a local worker factory.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class LocalWorkerState extends JDOSupport<PersistedState> implements
+		WorkerModel {
+	public LocalWorkerState() {
+		super(PersistedState.class);
+	}
+
+	private LocalWorkerState self;
+
+	@Required
+	public void setSelf(LocalWorkerState self) {
+		this.self = self;
+	}
+
+	/** Initial lifetime of runs, in minutes. */
+	int defaultLifetime;
+	/**
+	 * Maximum number of runs to exist at once. Note that this includes when
+	 * they are just existing for the purposes of file transfer (
+	 * {@link Status#Initialized}/{@link Status#Finished} states).
+	 */
+	int maxRuns;
+	/**
+	 * Prefix to use for RMI names.
+	 */
+	String factoryProcessNamePrefix;
+	/**
+	 * Full path name of the script used to start running a workflow; normally
+	 * expected to be "<i>somewhere/</i><tt>executeWorkflow.sh</tt>".
+	 */
+	String executeWorkflowScript;
+	/** Default value for {@link #executeWorkflowScript}. */
+	private transient String defaultExecuteWorkflowScript;
+	/**
+	 * Full path name of the file containing the password used to launch workers
+	 * as other users. The file is normally expected to contain a single line,
+	 * the password, and to be thoroughly locked down so only the user running
+	 * the server (e.g., "<tt>tomcat</tt>") can read it; it will probably reside
+	 * in either the user's home directory or in a system configuration
+	 * directory.
+	 */
+	String passwordFile;
+	/** Default value for {@link #passwordFile}. */
+	private transient String defaultPasswordFile = PASSWORD_FILE;
+	/**
+	 * The extra arguments to pass to the subprocess.
+	 */
+	String[] extraArgs;
+	/**
+	 * How long to wait for subprocess startup, in seconds.
+	 */
+	int waitSeconds;
+	/**
+	 * Polling interval to use during startup, in milliseconds.
+	 */
+	int sleepMS;
+	/**
+	 * Full path name to the worker process's implementation JAR.
+	 */
+	String serverWorkerJar;
+	private static final String DEFAULT_WORKER_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(SERVER_WORKER_IMPLEMENTATION_JAR)
+			.getFile();
+	/**
+	 * Full path name to the Java binary to use to run the subprocess.
+	 */
+	String javaBinary;
+	private static final String DEFAULT_JAVA_BINARY = getProperty("java.home")
+			+ separator + "bin" + separator + "java";
+	/**
+	 * Full path name to the secure fork process's implementation JAR.
+	 */
+	String serverForkerJar;
+	private static final String DEFAULT_FORKER_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(SECURE_FORK_IMPLEMENTATION_JAR)
+			.getFile();
+
+	String registryHost;
+	int registryPort;
+
+	int operatingLimit;
+
+	URI[] permittedWorkflows;
+	private String registryJar;
+	private static final String DEFAULT_REGISTRY_JAR = LocalWorkerState.class
+			.getClassLoader().getResource(REGISTRY_JAR).getFile();
+
+	@Override
+	public void setDefaultLifetime(int defaultLifetime) {
+		this.defaultLifetime = defaultLifetime;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getDefaultLifetime() {
+		return defaultLifetime < 1 ? RUN_LIFE_MINUTES : defaultLifetime;
+	}
+
+	@Override
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns < 1 ? Default.RUN_COUNT_MAX : maxRuns;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return operatingLimit < 1 ? RUN_OPERATING_LIMIT : operatingLimit;
+	}
+
+	@Override
+	public void setOperatingLimit(int operatingLimit) {
+		this.operatingLimit = operatingLimit;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
+		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getFactoryProcessNamePrefix() {
+		return factoryProcessNamePrefix == null ? RMI_PREFIX
+				: factoryProcessNamePrefix;
+	}
+
+	@Override
+	public void setExecuteWorkflowScript(String executeWorkflowScript) {
+		this.executeWorkflowScript = executeWorkflowScript;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getExecuteWorkflowScript() {
+		return executeWorkflowScript == null ? defaultExecuteWorkflowScript
+				: executeWorkflowScript;
+	}
+
+	private static String guessWorkflowScript() {
+		File utilDir = new File(DEFAULT_WORKER_JAR).getParentFile();
+		File[] dirs = utilDir.listFiles(new FilenameFilter() {
+			@Override
+			public boolean accept(File dir, String name) {
+				return name.startsWith("taverna-commandline-");
+			}
+		});
+		assert dirs.length > 0;
+		return new File(dirs[0], "executeworkflow.sh").toString();
+	}
+
+	/**
+	 * Set what executeworkflow script to use by default. This is the value that
+	 * is used if not overridden by the administration interface.
+	 * 
+	 * @param defaultScript
+	 *            Full path to the script to use.
+	 */
+	public void setDefaultExecuteWorkflowScript(String defaultScript) {
+		if (defaultScript.startsWith("${") || defaultScript.equals("NONE")) {
+			this.defaultExecuteWorkflowScript = guessWorkflowScript();
+			return;
+		}
+		this.defaultExecuteWorkflowScript = defaultScript;
+	}
+
+	String getDefaultExecuteWorkflowScript() {
+		return defaultExecuteWorkflowScript;
+	}
+
+	@Override
+	public void setExtraArgs(String[] extraArgs) {
+		this.extraArgs = extraArgs.clone();
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String[] getExtraArgs() {
+		return extraArgs == null ? EXTRA_ARGUMENTS : extraArgs.clone();
+	}
+
+	@Override
+	public void setWaitSeconds(int waitSeconds) {
+		this.waitSeconds = waitSeconds;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getWaitSeconds() {
+		return waitSeconds < 1 ? SUBPROCESS_START_WAIT : waitSeconds;
+	}
+
+	@Override
+	public void setSleepMS(int sleepMS) {
+		this.sleepMS = sleepMS;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getSleepMS() {
+		return sleepMS < 1 ? SUBPROCESS_START_POLL_SLEEP : sleepMS;
+	}
+
+	@Override
+	public void setServerWorkerJar(String serverWorkerJar) {
+		this.serverWorkerJar = serverWorkerJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getServerWorkerJar() {
+		return serverWorkerJar == null ? DEFAULT_WORKER_JAR : serverWorkerJar;
+	}
+
+	@Override
+	public void setServerForkerJar(String serverForkerJar) {
+		this.serverForkerJar = serverForkerJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getServerForkerJar() {
+		return serverForkerJar == null ? DEFAULT_FORKER_JAR : serverForkerJar;
+	}
+
+	@Override
+	public void setJavaBinary(String javaBinary) {
+		this.javaBinary = javaBinary;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getJavaBinary() {
+		return javaBinary == null ? DEFAULT_JAVA_BINARY : javaBinary;
+	}
+
+	@Override
+	public void setPasswordFile(String passwordFile) {
+		this.passwordFile = passwordFile;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getPasswordFile() {
+		return passwordFile == null ? defaultPasswordFile : passwordFile;
+	}
+
+	void setDefaultPasswordFile(String defaultPasswordFile) {
+		this.defaultPasswordFile = defaultPasswordFile;
+	}
+
+	@Override
+	public void setRegistryHost(String registryHost) {
+		this.registryHost = (registryHost == null ? "" : registryHost);
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public String getRegistryHost() {
+		return (registryHost == null || registryHost.isEmpty()) ? null
+				: registryHost;
+	}
+
+	@Override
+	public void setRegistryPort(int registryPort) {
+		this.registryPort = ((registryPort < 1 || registryPort > 65534) ? REGISTRY_PORT
+				: registryPort);
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public int getRegistryPort() {
+		return registryPort == 0 ? REGISTRY_PORT : registryPort;
+	}
+
+	@Override
+	public String getRegistryJar() {
+		return registryJar == null ? DEFAULT_REGISTRY_JAR : registryJar;
+	}
+
+	@Override
+	public void setRegistryJar(String rmiRegistryJar) {
+		this.registryJar = (rmiRegistryJar == null || rmiRegistryJar.isEmpty()) ? null
+				: rmiRegistryJar;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public List<URI> getPermittedWorkflowURIs() {
+		if (permittedWorkflows == null || permittedWorkflows.length == 0)
+			return emptyList();
+		return unmodifiableList(asList(permittedWorkflows));
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
+		if (permittedWorkflows == null || permittedWorkflows.isEmpty())
+			this.permittedWorkflows = new URI[0];
+		else
+			this.permittedWorkflows = permittedWorkflows
+					.toArray(new URI[permittedWorkflows.size()]);
+		if (loadedState)
+			self.store();
+	}
+
+	public static final boolean DEFAULT_GENERATE_PROVENANCE = false;
+	private Boolean generateProvenance;
+
+	@Override
+	public boolean getGenerateProvenance() {
+		Boolean g = generateProvenance;
+		return g == null ? DEFAULT_GENERATE_PROVENANCE : (boolean) g;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generate) {
+		this.generateProvenance = generate;
+		if (loadedState)
+			self.store();
+	}
+
+	// --------------------------------------------------------------
+
+	private boolean loadedState;
+
+	@PostConstruct
+	@WithinSingleTransaction
+	public void load() {
+		if (loadedState || !isPersistent())
+			return;
+		WorkerModel state = getById(KEY);
+		if (state == null) {
+			store();
+			return;
+		}
+
+		defaultLifetime = state.getDefaultLifetime();
+		executeWorkflowScript = state.getExecuteWorkflowScript();
+		extraArgs = state.getExtraArgs();
+		factoryProcessNamePrefix = state.getFactoryProcessNamePrefix();
+		javaBinary = state.getJavaBinary();
+		maxRuns = state.getMaxRuns();
+		serverWorkerJar = state.getServerWorkerJar();
+		serverForkerJar = state.getServerForkerJar();
+		passwordFile = state.getPasswordFile();
+		sleepMS = state.getSleepMS();
+		waitSeconds = state.getWaitSeconds();
+		registryHost = state.getRegistryHost();
+		registryPort = state.getRegistryPort();
+		operatingLimit = state.getOperatingLimit();
+		List<URI> pwu = state.getPermittedWorkflowURIs();
+		permittedWorkflows = (URI[]) pwu.toArray(new URI[pwu.size()]);
+		registryJar = state.getRegistryJar();
+		generateProvenance = state.getGenerateProvenance();
+
+		loadedState = true;
+	}
+
+	@WithinSingleTransaction
+	public void store() {
+		if (!isPersistent())
+			return;
+		WorkerModel state = getById(KEY);
+		if (state == null)
+			state = persist(makeInstance());
+
+		state.setDefaultLifetime(defaultLifetime);
+		state.setExecuteWorkflowScript(executeWorkflowScript);
+		state.setExtraArgs(extraArgs);
+		state.setFactoryProcessNamePrefix(factoryProcessNamePrefix);
+		state.setJavaBinary(javaBinary);
+		state.setMaxRuns(maxRuns);
+		state.setServerWorkerJar(serverWorkerJar);
+		state.setServerForkerJar(serverForkerJar);
+		state.setPasswordFile(passwordFile);
+		state.setSleepMS(sleepMS);
+		state.setWaitSeconds(waitSeconds);
+		state.setRegistryHost(registryHost);
+		state.setRegistryPort(registryPort);
+		state.setOperatingLimit(operatingLimit);
+		if (permittedWorkflows != null)
+			state.setPermittedWorkflowURIs(asList(permittedWorkflows));
+		state.setRegistryJar(registryJar);
+		if (generateProvenance != null)
+			state.setGenerateProvenance(generateProvenance);
+
+		loadedState = true;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
new file mode 100644
index 0000000..83d6bda
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.localworker;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jdo.annotations.Join;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The actual database connector for persisted local worker state.
+ * 
+ * @author Donal Fellows
+ */
+/*
+ * WARNING! If you change the name of this class, update persistence.xml as
+ * well!
+ */
+@PersistenceCapable(table = PersistedState.TABLE)
+class PersistedState implements WorkerModel {
+	static final String TABLE = "LOCALWORKERSTATE__PERSISTEDSTATE";
+
+	static PersistedState makeInstance() {
+		PersistedState o = new PersistedState();
+		o.ID = KEY;
+		return o;
+	}
+
+	@PrimaryKey(column = "ID")
+	protected int ID;
+
+	static final int KEY = 32;
+
+	@Persistent
+	private int defaultLifetime;
+	@Persistent
+	private int maxRuns;
+	@Persistent
+	private String factoryProcessNamePrefix;
+	@Persistent
+	private String executeWorkflowScript;
+	@Persistent(serialized = "true")
+	private String[] extraArgs;
+	@Persistent
+	private int waitSeconds;
+	@Persistent
+	private int sleepMS;
+	@Persistent
+	private String serverWorkerJar;
+	@Persistent
+	private String serverForkerJar;
+	@Persistent
+	private String registryJar;
+	@Persistent
+	private String passwordFile;
+	@Persistent
+	private String javaBinary;
+	@Persistent
+	private int registryPort;
+	@Persistent
+	private String registryHost;
+	@Persistent
+	private int operatingLimit;
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_PERMWFURI", column = "ID")
+	private String[] permittedWorkflows;
+	@Persistent
+	private int generateProvenance;
+
+	@Override
+	public void setDefaultLifetime(int defaultLifetime) {
+		this.defaultLifetime = defaultLifetime;
+	}
+
+	@Override
+	public int getDefaultLifetime() {
+		return defaultLifetime;
+	}
+
+	@Override
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns;
+	}
+
+	@Override
+	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
+		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
+	}
+
+	@Override
+	public String getFactoryProcessNamePrefix() {
+		return factoryProcessNamePrefix;
+	}
+
+	@Override
+	public void setExecuteWorkflowScript(String executeWorkflowScript) {
+		this.executeWorkflowScript = executeWorkflowScript;
+	}
+
+	@Override
+	public String getExecuteWorkflowScript() {
+		return executeWorkflowScript;
+	}
+
+	@Override
+	public void setExtraArgs(String[] extraArgs) {
+		this.extraArgs = extraArgs;
+	}
+
+	@Override
+	public String[] getExtraArgs() {
+		return extraArgs;
+	}
+
+	@Override
+	public void setWaitSeconds(int waitSeconds) {
+		this.waitSeconds = waitSeconds;
+	}
+
+	@Override
+	public int getWaitSeconds() {
+		return waitSeconds;
+	}
+
+	@Override
+	public void setSleepMS(int sleepMS) {
+		this.sleepMS = sleepMS;
+	}
+
+	@Override
+	public int getSleepMS() {
+		return sleepMS;
+	}
+
+	@Override
+	public void setServerWorkerJar(String serverWorkerJar) {
+		this.serverWorkerJar = serverWorkerJar;
+	}
+
+	@Override
+	public String getServerWorkerJar() {
+		return serverWorkerJar;
+	}
+
+	@Override
+	public void setJavaBinary(String javaBinary) {
+		this.javaBinary = javaBinary;
+	}
+
+	@Override
+	public String getJavaBinary() {
+		return javaBinary;
+	}
+
+	@Override
+	public void setRegistryPort(int registryPort) {
+		this.registryPort = registryPort;
+	}
+
+	@Override
+	public int getRegistryPort() {
+		return registryPort;
+	}
+
+	@Override
+	public void setRegistryHost(String registryHost) {
+		this.registryHost = registryHost;
+	}
+
+	@Override
+	public String getRegistryHost() {
+		return registryHost;
+	}
+
+	@Override
+	public void setServerForkerJar(String serverForkerJar) {
+		this.serverForkerJar = serverForkerJar;
+	}
+
+	@Override
+	public String getServerForkerJar() {
+		return serverForkerJar;
+	}
+
+	@Override
+	public void setPasswordFile(String passwordFile) {
+		this.passwordFile = passwordFile;
+	}
+
+	@Override
+	public String getPasswordFile() {
+		return passwordFile;
+	}
+
+	@Override
+	public void setOperatingLimit(int operatingLimit) {
+		this.operatingLimit = operatingLimit;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return operatingLimit;
+	}
+
+	@Override
+	public List<URI> getPermittedWorkflowURIs() {
+		String[] pw = this.permittedWorkflows;
+		if (pw == null)
+			return new ArrayList<>();
+		List<URI> uris = new ArrayList<>(pw.length);
+		for (String uri : pw)
+			uris.add(URI.create(uri));
+		return uris;
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
+		String[] pw = new String[permittedWorkflows.size()];
+		for (int i = 0; i < pw.length; i++)
+			pw[i] = permittedWorkflows.get(i).toString();
+		this.permittedWorkflows = pw;
+	}
+
+	@Override
+	public String getRegistryJar() {
+		return registryJar;
+	}
+
+	@Override
+	public void setRegistryJar(String registryJar) {
+		this.registryJar = registryJar;
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		return generateProvenance > 0;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		this.generateProvenance = (generateProvenance ? 1 : 0);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
new file mode 100644
index 0000000..f361e17
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
@@ -0,0 +1,62 @@
+package org.taverna.server.master.localworker;
+
+import static java.lang.Thread.interrupted;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.commons.logging.Log;
+
+abstract class StreamLogger {
+	protected final Log log;
+	private Thread t;
+	private InputStream in;
+
+	protected StreamLogger(final String name, InputStream is) {
+		log = getLog("Taverna.Server.LocalWorker." + name);
+		in = is;
+		t = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try (BufferedReader br = new BufferedReader(
+						new InputStreamReader(in))) {
+					String line;
+					while (!interrupted() && (line = br.readLine()) != null)
+						if (!line.isEmpty())
+							write(line);
+				} catch (IOException e) {
+					// Do nothing...
+				} catch (Exception e) {
+					log.warn("failure in reading from " + name, e);
+				}
+			}
+		}, name + ".StreamLogger");
+		t.setContextClassLoader(null);
+		t.setDaemon(true);
+		t.start();
+	}
+
+	/**
+	 * Write a line read from the subprocess to the log.
+	 * <p>
+	 * This needs to be implemented by subclasses in order for the log to be
+	 * correctly written with the class name.
+	 * 
+	 * @param msg
+	 *            The message to write. Guaranteed to have no newline characters
+	 *            in it and to be non-empty.
+	 */
+	protected abstract void write(String msg);
+
+	public void stop() {
+		log.info("trying to close down " + t.getName());
+		t.interrupt();
+		try {
+			in.close();
+		} catch (IOException e) {
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
new file mode 100644
index 0000000..7139dd7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Implementation of a Taverna Server back-end that works by forking off
+ * workflow executors on the local system.
+ */
+package org.taverna.server.master.localworker;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
new file mode 100644
index 0000000..3e27806
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.notification;
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.mail.MailSender;
+import org.springframework.mail.SimpleMailMessage;
+import org.springframework.mail.javamail.JavaMailSender;
+
+/**
+ * How to send a plain text message by email to someone.
+ * 
+ * @author Donal Fellows
+ */
+public class EmailDispatcher extends RateLimitedDispatcher {
+	@Override
+	public String getName() {
+		return "mailto";
+	}
+
+	/**
+	 * @param from
+	 *            Email address that the notification is to come from.
+	 */
+	@Required
+	public void setFrom(String from) {
+		this.from = valid(from, "");
+	}
+
+	/**
+	 * @param host
+	 *            The outgoing SMTP server address.
+	 */
+	@Required
+	public void setSmtpHost(String host) {
+		this.host = valid(host, "");
+	}
+
+	/**
+	 * @param contentType
+	 *            The content type of the message to be sent. For example, "
+	 *            <tt>text/plain</tt>".
+	 */
+	public void setMessageContentType(String contentType) {
+		this.contentType = contentType;
+	}
+
+	/**
+	 * @param sender
+	 *            the sender to set
+	 */
+	public void setSender(MailSender sender) {
+		this.sender = sender;
+	}
+
+	private String from;
+	private String host;
+	private MailSender sender;
+	@SuppressWarnings("unused")
+	private String contentType = TEXT_PLAIN;
+
+	/**
+	 * Try to perform the lookup of the email service. This is called during
+	 * configuration so that any failure happens at a useful, predictable time.
+	 */
+	@PostConstruct
+	public void tryLookup() {
+		if (!isAvailable()) {
+			log.warn("no mail support; disabling email dispatch");
+			sender = null;
+			return;
+		}
+		try {
+			if (sender instanceof JavaMailSender)
+				((JavaMailSender) sender).createMimeMessage();
+		} catch (Throwable t) {
+			log.warn("sender having problems constructing messages; "
+					+ "disabling...", t);
+			sender = null;
+		}
+	}
+
+	@Override
+	public void dispatch(String messageSubject, String messageContent, String to)
+			throws Exception {
+		// Simple checks for acceptability
+		if (!to.matches(".+@.+")) {
+			log.info("did not send email notification: improper email address \""
+					+ to + "\"");
+			return;
+		}
+
+		SimpleMailMessage message = new SimpleMailMessage();
+		message.setFrom(from);
+		message.setTo(to.trim());
+		message.setSubject(messageSubject);
+		message.setText(messageContent);
+		sender.send(message);
+	}
+
+	@Override
+	public boolean isAvailable() {
+		return (host != null && !host.isEmpty() && sender != null
+				&& from != null && !from.isEmpty());
+	}
+}


[18/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
new file mode 100644
index 0000000..184c7b5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/Admin.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.admin;
+
+import static org.taverna.server.master.admin.Paths.ALLOW_NEW;
+import static org.taverna.server.master.admin.Paths.ARGS;
+import static org.taverna.server.master.admin.Paths.EXEC_WF;
+import static org.taverna.server.master.admin.Paths.EXITCODE;
+import static org.taverna.server.master.admin.Paths.FACTORIES;
+import static org.taverna.server.master.admin.Paths.GEN_PROV;
+import static org.taverna.server.master.admin.Paths.INVOKES;
+import static org.taverna.server.master.admin.Paths.JAR_FORKER;
+import static org.taverna.server.master.admin.Paths.JAR_WORKER;
+import static org.taverna.server.master.admin.Paths.JAVA;
+import static org.taverna.server.master.admin.Paths.LIFE;
+import static org.taverna.server.master.admin.Paths.LOG_EXN;
+import static org.taverna.server.master.admin.Paths.LOG_WFS;
+import static org.taverna.server.master.admin.Paths.OPERATING;
+import static org.taverna.server.master.admin.Paths.OP_LIMIT;
+import static org.taverna.server.master.admin.Paths.PASSFILE;
+import static org.taverna.server.master.admin.Paths.PERM_WF;
+import static org.taverna.server.master.admin.Paths.REG_HOST;
+import static org.taverna.server.master.admin.Paths.REG_JAR;
+import static org.taverna.server.master.admin.Paths.REG_POLL;
+import static org.taverna.server.master.admin.Paths.REG_PORT;
+import static org.taverna.server.master.admin.Paths.REG_WAIT;
+import static org.taverna.server.master.admin.Paths.ROOT;
+import static org.taverna.server.master.admin.Paths.RUNS;
+import static org.taverna.server.master.admin.Paths.RUN_LIMIT;
+import static org.taverna.server.master.admin.Paths.STARTUP;
+import static org.taverna.server.master.admin.Paths.TOTAL_RUNS;
+import static org.taverna.server.master.admin.Paths.URS;
+import static org.taverna.server.master.admin.Paths.UR_FILE;
+import static org.taverna.server.master.admin.Paths.USER;
+import static org.taverna.server.master.admin.Paths.USERS;
+import static org.taverna.server.master.admin.Types.JSON;
+import static org.taverna.server.master.admin.Types.PLAIN;
+import static org.taverna.server.master.admin.Types.XML;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.ogf.usage.JobUsageRecord;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+
+/**
+ * The administration interface for Taverna Server.
+ * 
+ * @author Donal Fellows
+ */
+@Description("Administration interface for Taverna Server.")
+public interface Admin {
+	/**
+	 * Get a simple administration user interface.
+	 * 
+	 * @return The description document in a response.
+	 * @throws IOException
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces("text/html")
+	@Nonnull
+	Response getUserInterface() throws IOException;
+
+	/**
+	 * Gets support resources for the administration user interface.
+	 * 
+	 * @param file
+	 *            The name of the static resource to provide.
+	 * @return The requested document in a response.
+	 * @throws IOException
+	 */
+	@GET
+	@Path("static/{file}")
+	@Produces("*/*")
+	Response getStaticResource(@PathParam("file") String file)
+			throws IOException;
+
+	/**
+	 * Get a description of the administration interface.
+	 * 
+	 * @param ui
+	 *            What URI was used to access this resource?
+	 * @return The description document.
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces({ XML, JSON })
+	@Nonnull
+	AdminDescription getDescription(@Context UriInfo ui);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ROOT)
+	Response optionsRoot();
+
+	/**
+	 * Get whether to allow new workflow runs to be created.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(ALLOW_NEW)
+	@Produces(PLAIN)
+	@Description("Whether to allow new workflow runs to be created.")
+	boolean getAllowNew();
+
+	/**
+	 * Set whether to allow new workflow runs to be created.
+	 * 
+	 * @param newValue
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(ALLOW_NEW)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to allow new workflow runs to be created.")
+	boolean setAllowNew(boolean newValue);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ALLOW_NEW)
+	@Description("Whether to allow new workflow runs to be created.")
+	Response optionsAllowNew();
+
+	/**
+	 * Get whether to log the workflows submitted.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LOG_WFS)
+	@Produces(PLAIN)
+	@Description("Whether to log the workflows submitted.")
+	boolean getLogWorkflows();
+
+	/**
+	 * Set whether to log the workflows submitted.
+	 * 
+	 * @param logWorkflows
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LOG_WFS)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to log the workflows submitted.")
+	boolean setLogWorkflows(boolean logWorkflows);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LOG_WFS)
+	@Description("Whether to log the workflows submitted.")
+	Response optionsLogWorkflows();
+
+	/**
+	 * Get whether to log the user-directed faults.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LOG_EXN)
+	@Produces(PLAIN)
+	@Description("Whether to log the user-directed faults.")
+	boolean getLogFaults();
+
+	/**
+	 * Set whether to log the user-directed faults.
+	 * 
+	 * @param logFaults
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LOG_EXN)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Whether to log the user-directed faults.")
+	boolean setLogFaults(boolean logFaults);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LOG_EXN)
+	@Description("Whether to log the user-directed faults.")
+	Response optionsLogFaults();
+
+	/**
+	 * Get what file to dump usage records to.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(UR_FILE)
+	@Produces(PLAIN)
+	@Description("What file to dump usage records to.")
+	@Nonnull
+	String getURFile();
+
+	/**
+	 * Set what file to dump usage records to.
+	 * 
+	 * @param urFile
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(UR_FILE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What file to dump usage records to.")
+	@Nonnull
+	String setURFile(@Nonnull String urFile);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(UR_FILE)
+	@Description("What file to dump usage records to.")
+	Response optionsURFile();
+
+	/**
+	 * The property for the number of times the service methods have been
+	 * invoked.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(INVOKES)
+	@Produces(PLAIN)
+	@Description("How many times have the service methods been invoked.")
+	int invokeCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(INVOKES)
+	@Description("How many times have the service methods been invoked.")
+	Response optionsInvokationCount();
+
+	/**
+	 * The property for the number of runs that are currently in existence.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(TOTAL_RUNS)
+	@Produces(PLAIN)
+	@Description("How many runs are currently in existence.")
+	int runCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(TOTAL_RUNS)
+	@Description("How many runs are currently in existence.")
+	Response optionsRunCount();
+
+	/**
+	 * The property for the number of runs that are currently running.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(OPERATING)
+	@Produces(PLAIN)
+	@Description("How many runs are currently actually running.")
+	int operatingCount();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(OPERATING)
+	@Description("How many runs are currently actually running.")
+	Response optionsOperatingCount();
+
+	/**
+	 * Get the full pathname of the RMI registry's JAR.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_JAR)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
+	@Nonnull
+	String getRegistryJar();
+
+	/**
+	 * Set the full pathname of the RMI registry's JAR.
+	 * 
+	 * @param registryJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_JAR)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's custom RMI registry executable JAR file?")
+	@Nonnull
+	String setRegistryJar(@Nonnull String registryJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_JAR)
+	@Description("What is the full pathname of the server's special custom RMI registry executable JAR file?")
+	Response optionsRegistryJar();
+
+	/**
+	 * Get the location of the RMI registry.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_HOST)
+	@Produces(PLAIN)
+	@Description("Where is the RMI registry?")
+	@Nonnull
+	String getRegistryHost();
+
+	/**
+	 * Set the location of the RMI registry.
+	 * 
+	 * @param registryHost
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_HOST)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Where is the RMI registry?")
+	@Nonnull
+	String setRegistryHost(@Nonnull String registryHost);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_HOST)
+	@Description("Where is the RMI registry?")
+	Response optionsRegistryHost();
+
+	/**
+	 * Get the port of the RMI registry.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_PORT)
+	@Produces(PLAIN)
+	@Description("On what port is the RMI registry?")
+	int getRegistryPort();
+
+	/**
+	 * Set the port of the RMI registry.
+	 * 
+	 * @param registryPort
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_PORT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("On what port is the RMI registry?")
+	int setRegistryPort(int registryPort);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_PORT)
+	@Description("On what port is the RMI registry?")
+	Response optionsRegistryPort();
+
+	/**
+	 * Get the maximum number of simultaneous runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(RUN_LIMIT)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous runs?")
+	int getRunLimit();
+
+	/**
+	 * Set the maximum number of simultaneous runs.
+	 * 
+	 * @param runLimit
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(RUN_LIMIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous runs?")
+	int setRunLimit(int runLimit);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(RUN_LIMIT)
+	@Description("What is the maximum number of simultaneous runs?")
+	Response optionsRunLimit();
+
+	/**
+	 * Get the maximum number of simultaneous executing runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(OP_LIMIT)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	int getOperatingLimit();
+
+	/**
+	 * Set the maximum number of simultaneous executing runs.
+	 * 
+	 * @param operatingLimit
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(OP_LIMIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	int setOperatingLimit(int operatingLimit);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(OP_LIMIT)
+	@Description("What is the maximum number of simultaneous executing runs?")
+	Response optionsOperatingLimit();
+
+	/**
+	 * Get the default lifetime of workflow runs.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(LIFE)
+	@Produces(PLAIN)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	int getDefaultLifetime();
+
+	/**
+	 * Set the default lifetime of workflow runs.
+	 * 
+	 * @param defaultLifetime
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(LIFE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	int setDefaultLifetime(int defaultLifetime);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(LIFE)
+	@Description("What is the default lifetime of workflow runs, in seconds?")
+	Response optionsDefaultLifetime();
+
+	/**
+	 * The property for the list of IDs of current runs.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(RUNS)
+	@Produces({ XML, JSON })
+	@Description("List the IDs of all current runs.")
+	StringList currentRuns();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(RUNS)
+	@Description("List the IDs of all current runs.")
+	Response optionsCurrentRuns();
+
+	/**
+	 * Get the Java binary to be used for execution of subprocesses.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAVA)
+	@Produces(PLAIN)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	@Nonnull
+	String getJavaBinary();
+
+	/**
+	 * Set the Java binary to be used for execution of subprocesses.
+	 * 
+	 * @param javaBinary
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAVA)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	@Nonnull
+	String setJavaBinary(@Nonnull String javaBinary);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAVA)
+	@Description("Which Java binary should be used for execution of subprocesses?")
+	Response optionsJavaBinary();
+
+	/**
+	 * Get the extra arguments to be supplied to Java subprocesses.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(ARGS)
+	@Produces({ XML, JSON })
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	@Nonnull
+	StringList getExtraArguments();
+
+	/**
+	 * Set the extra arguments to be supplied to Java subprocesses.
+	 * 
+	 * @param extraArguments
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(ARGS)
+	@Consumes(XML)
+	@Produces({ XML, JSON })
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	@Nonnull
+	StringList setExtraArguments(@Nonnull StringList extraArguments);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(ARGS)
+	@Description("What extra arguments should be supplied to Java subprocesses?")
+	Response optionsExtraArguments();
+
+	/**
+	 * Get the full pathname of the worker JAR file.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAR_WORKER)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	@Nonnull
+	String getServerWorkerJar();
+
+	/**
+	 * Set the full pathname of the worker JAR file.
+	 * 
+	 * @param serverWorkerJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAR_WORKER)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	@Nonnull
+	String setServerWorkerJar(@Nonnull String serverWorkerJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAR_WORKER)
+	@Description("What is the full pathname of the server's per-user worker executable JAR file?")
+	Response optionsServerWorkerJar();
+
+	/**
+	 * Get the full pathname of the executeWorkflow.sh file.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(EXEC_WF)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	@Nonnull
+	String getExecuteWorkflowScript();
+
+	/**
+	 * Set the full pathname of the executeWorkflow.sh file.
+	 * 
+	 * @param executeWorkflowScript
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(EXEC_WF)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	@Nonnull
+	String setExecuteWorkflowScript(@Nonnull String executeWorkflowScript);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(EXEC_WF)
+	@Description("What is the full pathname of the core Taverna executeWorkflow script?")
+	Response optionsExecuteWorkflowScript();
+
+	/**
+	 * Get the total duration of time to wait for the start of the forker
+	 * process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_WAIT)
+	@Produces(PLAIN)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	int getRegistrationWaitSeconds();
+
+	/**
+	 * Set the total duration of time to wait for the start of the forker
+	 * process.
+	 * 
+	 * @param registrationWaitSeconds
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_WAIT)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	int setRegistrationWaitSeconds(int registrationWaitSeconds);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_WAIT)
+	@Description("How long in total should the core wait for registration of the \"forker\" process, in seconds.")
+	Response optionsRegistrationWaitSeconds();
+
+	/**
+	 * Get the interval between checks for registration of the forker process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(REG_POLL)
+	@Produces(PLAIN)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	int getRegistrationPollMillis();
+
+	/**
+	 * Set the interval between checks for registration of the forker process.
+	 * 
+	 * @param registrationPollMillis
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(REG_POLL)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	int setRegistrationPollMillis(int registrationPollMillis);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(REG_POLL)
+	@Description("What is the interval between checks for registration of the \"forker\" process, in milliseconds.")
+	Response optionsRegistrationPollMillis();
+
+	/**
+	 * Get the full pathname of the file containing the impersonation
+	 * credentials for the forker process.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(PASSFILE)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	@Nonnull
+	String getRunasPasswordFile();
+
+	/**
+	 * Set the full pathname of the file containing the impersonation
+	 * credentials for the forker process.
+	 * 
+	 * @param runasPasswordFile
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(PASSFILE)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	@Nonnull
+	String setRunasPasswordFile(@Nonnull String runasPasswordFile);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(PASSFILE)
+	@Description("What is the full pathname of the file containing the password used for impersonating other users? (On Unix, this is the password for the deployment user to use \"sudo\".)")
+	Response optionsRunasPasswordFile();
+
+	/**
+	 * Get the full pathname of the forker's JAR.
+	 * 
+	 * @return The current setting.
+	 */
+	@GET
+	@Path(JAR_FORKER)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	@Nonnull
+	String getServerForkerJar();
+
+	/**
+	 * Set the full pathname of the forker's JAR.
+	 * 
+	 * @param serverForkerJar
+	 *            What to set it to.
+	 * @return The new setting.
+	 */
+	@PUT
+	@Path(JAR_FORKER)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	@Nonnull
+	String setServerForkerJar(@Nonnull String serverForkerJar);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(JAR_FORKER)
+	@Description("What is the full pathname of the server's special authorized \"forker\" executable JAR file?")
+	Response optionsServerForkerJar();
+
+	/**
+	 * The property for the length of time it took to start the forker.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(STARTUP)
+	@Produces(PLAIN)
+	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
+	int startupTime();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(STARTUP)
+	@Description("How long did it take for the back-end \"forker\" to set itself up, in seconds.")
+	Response optionsStartupTime();
+
+	/**
+	 * The property for the last exit code of the forker process.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(EXITCODE)
+	@Produces(PLAIN)
+	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
+	Integer lastExitCode();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(EXITCODE)
+	@Description("What was the last exit code of the \"forker\"? If null, no exit has ever been recorded.")
+	Response optionsLastExitCode();
+
+	/**
+	 * The property for the mapping of usernames to factory process handles.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(FACTORIES)
+	@Produces({ XML, JSON })
+	@Description("What is the mapping of local usernames to factory process RMI IDs?")
+	StringList factoryProcessMapping();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(FACTORIES)
+	@Description("What is the mapping of local usernames to factory process RMI IDs?")
+	Response optionsFactoryProcessMapping();
+
+	/**
+	 * The property for the list of usage records collected.
+	 * 
+	 * @return The property value (read-only).
+	 */
+	@GET
+	@Path(URS)
+	@Produces(XML)
+	@Description("What is the list of usage records that have been collected?")
+	URList usageRecords();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(URS)
+	@Description("What is the list of usage records that have been collected?")
+	Response optionsUsageRecords();
+
+	/**
+	 * What are the current list of workflow URIs that may be started? Empty
+	 * means allow any, including user-supplied workflows.
+	 * 
+	 * @return List of URIs, encoded as strings.
+	 */
+	@GET
+	@Path(PERM_WF)
+	@Produces({ XML, JSON })
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	StringList getPermittedWorkflowURIs();
+
+	/** Do we turn on the generate provenance option by default? */
+	@GET
+	@Path(GEN_PROV)
+	@Produces(PLAIN)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	String getGenerateProvenance();
+
+	/** Do we turn on the generate provenance option by default? */
+	@PUT
+	@Path(GEN_PROV)
+	@Consumes(PLAIN)
+	@Produces(PLAIN)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	String setGenerateProvenance(String newValue);
+
+	/** Do we turn on the generate provenance option by default? */
+	@OPTIONS
+	@Path(GEN_PROV)
+	@Description("Do we turn on the generate provenance option by default? (boolean)")
+	Response optionsGenerateProvenance();
+
+	/**
+	 * What are the current list of workflow URIs that may be started? Empty
+	 * means allow any, including user-supplied workflows.
+	 * 
+	 * @param permitted
+	 *            List of URIs, encoded as strings.
+	 * @return List of URIs, encoded as strings.
+	 */
+	@PUT
+	@Path(PERM_WF)
+	@Consumes(XML)
+	@Produces({ XML, JSON })
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	StringList setPermittedWorkflowURIs(@Nonnull StringList permitted);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(PERM_WF)
+	@Description("What are the current list of workflow URIs that may be started? Empty means allow any, including user-supplied workflows.")
+	Response optionsPermittedWorkflowURIs();
+
+	@GET
+	@Path(USERS)
+	@Produces({ XML, JSON })
+	@Description("What users are known to the server?")
+	UserList users(@Context UriInfo ui);
+
+	@GET
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Description("What do we know about a particular user?")
+	UserDesc user(@PathParam("id") String username);
+
+	@POST
+	@Path(USERS)
+	@Consumes(XML)
+	@Description("Create a user.")
+	Response useradd(UserDesc userdesc, @Nonnull @Context UriInfo ui);
+
+	@PUT
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Consumes(XML)
+	@Description("Update a user.")
+	UserDesc userset(@PathParam("id") String username, UserDesc userdesc);
+
+	@DELETE
+	@Path(USER)
+	@Produces({ XML, JSON })
+	@Description("What do we know about a particular user?")
+	Response userdel(@PathParam("id") String username);
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(USERS)
+	@Description("What users are known to the server?")
+	Response optionsUsers();
+
+	/** What HTTP methods may we use? */
+	@OPTIONS
+	@Path(USER)
+	@Description("What do we know about a particular user?")
+	Response optionsUser(@PathParam("id") String username);
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * The description of what properties are supported by the administration
+	 * interface.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "description")
+	@XmlType(name = "Description")
+	public static class AdminDescription extends VersionedElement {
+		public Uri allowNew;
+		public Uri logWorkflows;
+		public Uri logFaults;
+		public Uri usageRecordDumpFile;
+		public Uri invokationCount;
+		public Uri runCount;
+		public Uri registryHost;
+		public Uri registryPort;
+		public Uri runLimit;
+		public Uri defaultLifetime;
+		public Uri currentRuns;
+		public Uri javaBinary;
+		public Uri extraArguments;
+		public Uri serverWorkerJar;
+		public Uri serverForkerJar;
+		public Uri executeWorkflowScript;
+		public Uri registrationWaitSeconds;
+		public Uri registrationPollMillis;
+		public Uri runasPasswordFile;
+		public Uri startupTime;
+		public Uri lastExitCode;
+		public Uri factoryProcessMapping;
+		public Uri usageRecords;
+		public Uri users;
+		public Uri operatingLimit;
+		public Uri operatingCount;
+		public Uri permittedWorkflowURIs;
+		public Uri generateProvenance;
+
+		public AdminDescription() {
+		}
+
+		public AdminDescription(UriInfo ui) {
+			allowNew = new Uri(ui, ALLOW_NEW);
+			logWorkflows = new Uri(ui, LOG_WFS);
+			logFaults = new Uri(ui, LOG_EXN);
+			usageRecordDumpFile = new Uri(ui, UR_FILE);
+			invokationCount = new Uri(ui, INVOKES);
+			runCount = new Uri(ui, TOTAL_RUNS);
+			registryHost = new Uri(ui, REG_HOST);
+			registryPort = new Uri(ui, REG_PORT);
+			runLimit = new Uri(ui, RUN_LIMIT);
+			defaultLifetime = new Uri(ui, LIFE);
+			currentRuns = new Uri(ui, RUNS);
+			javaBinary = new Uri(ui, JAVA);
+			extraArguments = new Uri(ui, ARGS);
+			serverWorkerJar = new Uri(ui, JAR_WORKER);
+			serverForkerJar = new Uri(ui, JAR_FORKER);
+			executeWorkflowScript = new Uri(ui, EXEC_WF);
+			registrationWaitSeconds = new Uri(ui, REG_WAIT);
+			registrationPollMillis = new Uri(ui, REG_POLL);
+			runasPasswordFile = new Uri(ui, PASSFILE);
+			startupTime = new Uri(ui, STARTUP);
+			lastExitCode = new Uri(ui, EXITCODE);
+			factoryProcessMapping = new Uri(ui, FACTORIES);
+			usageRecords = new Uri(ui, URS);
+			users = new Uri(ui, USERS);
+			operatingLimit = new Uri(ui, OP_LIMIT);
+			operatingCount = new Uri(ui, OPERATING);
+			permittedWorkflowURIs = new Uri(ui, PERM_WF);
+			generateProvenance = new Uri(ui, GEN_PROV);
+		}
+	}
+
+	/**
+	 * A list of strings, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "stringList")
+	@XmlType(name = "StringList")
+	public static class StringList {
+		@XmlElement
+		public List<String> string = new ArrayList<>();
+	}
+
+	/**
+	 * A list of users, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "userList")
+	@XmlType(name = "UserList")
+	public static class UserList {
+		@XmlElement
+		public List<URI> user = new ArrayList<>();
+	}
+
+	@XmlRootElement(name = "userDesc")
+	@XmlType(name = "UserDesc")
+	public static class UserDesc {
+		@XmlElement
+		public String username;
+		@XmlElement
+		public String password;
+		@XmlElement
+		public String localUserId;
+		@XmlElement
+		public Boolean enabled;
+		@XmlElement
+		public Boolean admin;
+	}
+
+	/**
+	 * A list of usage records, as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "usageRecordList")
+	@XmlType(name = "UsageRecords")
+	public static class URList {
+		@XmlElement
+		public List<JobUsageRecord> usageRecord;
+	}
+}
+
+interface Paths {
+	static final String ROOT = "/";
+	static final String ALLOW_NEW = "allowNew";
+	static final String LOG_WFS = "logWorkflows";
+	static final String LOG_EXN = "logFaults";
+	static final String UR_FILE = "usageRecordDumpFile";
+	static final String INVOKES = "invokationCount";
+	static final String TOTAL_RUNS = "runCount";
+	static final String OPERATING = "operatingCount";
+	static final String REG_HOST = "registryHost";
+	static final String REG_PORT = "registryPort";
+	static final String REG_JAR = "registryJar";
+	static final String RUN_LIMIT = "runLimit";
+	static final String OP_LIMIT = "operatingLimit";
+	static final String LIFE = "defaultLifetime";
+	static final String RUNS = "currentRuns";
+	static final String JAVA = "javaBinary";
+	static final String ARGS = "extraArguments";
+	static final String JAR_WORKER = "serverWorkerJar";
+	static final String JAR_FORKER = "serverForkerJar";
+	static final String EXEC_WF = "executeWorkflowScript";
+	static final String REG_WAIT = "registrationWaitSeconds";
+	static final String REG_POLL = "registrationPollMillis";
+	static final String PASSFILE = "runasPasswordFile";
+	static final String STARTUP = "startupTime";
+	static final String EXITCODE = "lastExitCode";
+	static final String FACTORIES = "factoryProcessMapping";
+	static final String URS = "usageRecords";
+	static final String PERM_WF = "permittedWorkflowURIs";
+	static final String GEN_PROV = "generateProvenance";
+	static final String USERS = "users";
+	static final String USER = USERS + "/{id}";
+}
+
+interface Types {
+	static final String PLAIN = "text/plain";
+	static final String XML = "application/xml";
+	static final String JSON = "application/json";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
new file mode 100644
index 0000000..b83d88f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/AdminBean.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.admin;
+
+import static java.util.Arrays.asList;
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+import static org.taverna.server.master.common.Roles.ADMIN;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.exceptions.GeneralFailureException;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.identity.User;
+import org.taverna.server.master.identity.UserStoreAPI;
+import org.taverna.server.master.usage.UsageRecordRecorder;
+import org.taverna.server.master.utils.InvocationCounter;
+import org.taverna.server.master.worker.RunDBSupport;
+import org.taverna.server.master.worker.WorkerModel;
+
+/**
+ * The administration interface to Taverna Server.
+ * 
+ * @author Donal Fellows
+ */
+public class AdminBean implements Admin {
+	@Required
+	public void setState(ManagementModel state) {
+		this.state = state;
+	}
+
+	@Required
+	public void setCounter(InvocationCounter counter) {
+		this.counter = counter;
+	}
+
+	@Required
+	public void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	@Required
+	public void setFactory(ConfigurableRunFactory factory) {
+		this.factory = factory;
+	}
+
+	@Required
+	public void setUsageRecords(UsageRecordRecorder usageRecords) {
+		this.usageRecords = usageRecords;
+	}
+
+	@Required
+	public void setUserStore(UserStoreAPI userStore) {
+		this.userStore = userStore;
+	}
+
+	@Required
+	public void setLocalWorkerModel(WorkerModel worker) {
+		localWorker = worker;
+	}
+
+	public void setAdminHtmlFile(String filename) {
+		this.adminHtmlFile = filename;
+	}
+
+	public void setResourceRoot(String root) {
+		this.resourceRoot = root;
+	}
+
+	protected byte[] getResource(String name) throws IOException {
+		if (AdminBean.class.getResource(name) == null)
+			throw new FileNotFoundException(name);
+		return IOUtils.toByteArray(AdminBean.class.getResourceAsStream(name));
+	}
+
+	private ManagementModel state;
+	private InvocationCounter counter;
+	private RunDBSupport runDB;
+	private ConfigurableRunFactory factory;
+	private UsageRecordRecorder usageRecords;
+	private UserStoreAPI userStore;
+	private WorkerModel localWorker;
+	private String adminHtmlFile = "/admin.html";
+	private String resourceRoot = "/static/";
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response getUserInterface() throws IOException {
+		return Response.ok(getResource(adminHtmlFile), "text/html").build();
+	}
+
+	@Override
+	@RolesAllowed(ADMIN)
+	public Response getStaticResource(String file) throws IOException {
+		if (file.matches("^[-_.a-zA-Z0-9]+$")) {
+			String type = "application/octet-stream";
+			if (file.endsWith(".html"))
+				type = "text/html";
+			else if (file.endsWith(".js"))
+				type = "text/javascript";
+			else if (file.endsWith(".jpg"))
+				type = "image/jpeg";
+			else if (file.endsWith(".gif"))
+				type = "image/gif";
+			else if (file.endsWith(".png"))
+				type = "image/png";
+			else if (file.endsWith(".svg"))
+				type = "image/svg+xml";
+			else if (file.endsWith(".css"))
+				type = "text/css";
+			try {
+				return Response.ok(getResource(resourceRoot + file), type)
+						.build();
+			} catch (IOException e) {
+				// ignore; we just treat as 404
+			}
+		}
+		return Response.status(NOT_FOUND).entity("no such resource").build();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public AdminDescription getDescription(UriInfo ui) {
+		return new AdminDescription(ui);
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRoot() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getAllowNew() {
+		return state.getAllowNewWorkflowRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setAllowNew(boolean newValue) {
+		state.setAllowNewWorkflowRuns(newValue);
+		return state.getAllowNewWorkflowRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsAllowNew() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getLogWorkflows() {
+		return state.getLogIncomingWorkflows();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setLogWorkflows(boolean newValue) {
+		state.setLogIncomingWorkflows(newValue);
+		return state.getLogIncomingWorkflows();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLogWorkflows() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean getLogFaults() {
+		return state.getLogOutgoingExceptions();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public boolean setLogFaults(boolean newValue) {
+		state.setLogOutgoingExceptions(newValue);
+		return state.getLogOutgoingExceptions();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLogFaults() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getURFile() {
+		return state.getUsageRecordLogFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setURFile(String newValue) {
+		state.setUsageRecordLogFile(newValue);
+		return state.getUsageRecordLogFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsURFile() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int invokeCount() {
+		return counter.getCount();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsInvokationCount() {
+		return opt();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int runCount() {
+		return runDB.countRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRunCount() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRegistryHost() {
+		return factory.getRegistryHost();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRegistryHost(String newValue) {
+		factory.setRegistryHost(newValue);
+		return factory.getRegistryHost();
+	}
+
+	@Override
+	public Response optionsRegistryHost() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistryPort() {
+		return factory.getRegistryPort();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistryPort(int newValue) {
+		factory.setRegistryPort(newValue);
+		return factory.getRegistryPort();
+	}
+
+	@Override
+	public Response optionsRegistryPort() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRegistryJar() {
+		return factory.getRmiRegistryJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRegistryJar(String registryJar) {
+		factory.setRmiRegistryJar(registryJar);
+		return factory.getRmiRegistryJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistryJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRunLimit() {
+		return factory.getMaxRuns();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRunLimit(int newValue) {
+		factory.setMaxRuns(newValue);
+		return factory.getMaxRuns();
+	}
+
+	@Override
+	public Response optionsRunLimit() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getDefaultLifetime() {
+		return factory.getDefaultLifetime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setDefaultLifetime(int newValue) {
+		factory.setDefaultLifetime(newValue);
+		return factory.getDefaultLifetime();
+	}
+
+	@Override
+	public Response optionsDefaultLifetime() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList currentRuns() {
+		StringList result = new StringList();
+		result.string = runDB.listRunNames();
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsCurrentRuns() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getJavaBinary() {
+		return factory.getJavaBinary();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setJavaBinary(String newValue) {
+		factory.setJavaBinary(newValue);
+		return factory.getJavaBinary();
+	}
+
+	@Override
+	public Response optionsJavaBinary() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList getExtraArguments() {
+		String[] xargs = factory.getExtraArguments();
+		StringList result = new StringList();
+		result.string = asList(xargs == null ? new String[0] : xargs);
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList setExtraArguments(StringList newValue) {
+		if (newValue == null || newValue.string == null)
+			factory.setExtraArguments(new String[0]);
+		else
+			factory.setExtraArguments(newValue.string
+					.toArray(new String[newValue.string.size()]));
+		StringList result = new StringList();
+		result.string = asList(factory.getExtraArguments());
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsExtraArguments() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getServerWorkerJar() {
+		return factory.getServerWorkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setServerWorkerJar(String newValue) {
+		factory.setServerWorkerJar(newValue);
+		return factory.getServerWorkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsServerWorkerJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getExecuteWorkflowScript() {
+		return factory.getExecuteWorkflowScript();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setExecuteWorkflowScript(String newValue) {
+		factory.setExecuteWorkflowScript(newValue);
+		return factory.getExecuteWorkflowScript();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsExecuteWorkflowScript() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistrationWaitSeconds() {
+		return factory.getWaitSeconds();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistrationWaitSeconds(int newValue) {
+		factory.setWaitSeconds(newValue);
+		return factory.getWaitSeconds();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistrationWaitSeconds() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getRegistrationPollMillis() {
+		return factory.getSleepTime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setRegistrationPollMillis(int newValue) {
+		factory.setSleepTime(newValue);
+		return factory.getSleepTime();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRegistrationPollMillis() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getRunasPasswordFile() {
+		return factory.getPasswordFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setRunasPasswordFile(String newValue) {
+		factory.setPasswordFile(newValue);
+		return factory.getPasswordFile();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsRunasPasswordFile() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getServerForkerJar() {
+		return factory.getServerForkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setServerForkerJar(String newValue) {
+		factory.setServerForkerJar(newValue);
+		return factory.getServerForkerJar();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsServerForkerJar() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int startupTime() {
+		return factory.getLastStartupCheckCount();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsStartupTime() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Integer lastExitCode() {
+		return factory.getLastExitCode();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsLastExitCode() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList factoryProcessMapping() {
+		StringList result = new StringList();
+		result.string = asList(factory.getFactoryProcessMapping());
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsFactoryProcessMapping() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public URList usageRecords() {
+		URList result = new URList();
+		result.usageRecord = usageRecords.getUsageRecords();
+		return result;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUsageRecords() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserList users(UriInfo ui) {
+		UserList ul = new UserList();
+		UriBuilder ub = secure(ui).path("{id}");
+		for (String user : userStore.getUserNames())
+			ul.user.add(ub.build(user));
+		return ul;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUsers() {
+		return opt("POST");
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserDesc user(String username) {
+		UserDesc desc = new UserDesc();
+		User u = userStore.getUser(username);
+		desc.username = u.getUsername();
+		desc.localUserId = u.getLocalUsername();
+		desc.admin = u.isAdmin();
+		desc.enabled = u.isEnabled();
+		return desc;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsUser(String username) {
+		return opt("PUT", "DELETE");
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response useradd(UserDesc userdesc, UriInfo ui) {
+		if (userdesc.username == null)
+			throw new IllegalArgumentException("no user name supplied");
+		if (userdesc.password == null)
+			userdesc.password = randomUUID().toString();
+		userStore.addUser(userdesc.username, userdesc.password, false);
+		if (userdesc.localUserId != null)
+			userStore.setUserLocalUser(userdesc.username, userdesc.localUserId);
+		if (userdesc.admin != null && userdesc.admin)
+			userStore.setUserAdmin(userdesc.username, true);
+		if (userdesc.enabled != null && userdesc.enabled)
+			userStore.setUserEnabled(userdesc.username, true);
+		return created(secure(ui).path("{id}").build(userdesc.username))
+				.build();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public UserDesc userset(String username, UserDesc userdesc) {
+		if (userdesc.password != null)
+			userStore.setUserPassword(username, userdesc.password);
+		if (userdesc.localUserId != null)
+			userStore.setUserLocalUser(username, userdesc.localUserId);
+		if (userdesc.admin != null)
+			userStore.setUserAdmin(username, userdesc.admin);
+		if (userdesc.enabled != null)
+			userStore.setUserEnabled(username, userdesc.enabled);
+		userdesc = null; // Stop reuse!
+
+		UserDesc desc = new UserDesc();
+		User u = userStore.getUser(username);
+		desc.username = u.getUsername();
+		desc.localUserId = u.getLocalUsername();
+		desc.admin = u.isAdmin();
+		desc.enabled = u.isEnabled();
+		return desc;
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response userdel(String username) {
+		userStore.deleteUser(username);
+		return noContent().build();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int operatingCount() {
+		try {
+			return factory.getOperatingCount();
+		} catch (Exception e) {
+			throw new GeneralFailureException(e);
+		}
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsOperatingCount() {
+		return opt();
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int getOperatingLimit() {
+		return factory.getOperatingLimit();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public int setOperatingLimit(int operatingLimit) {
+		factory.setOperatingLimit(operatingLimit);
+		return factory.getOperatingLimit();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsOperatingLimit() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList getPermittedWorkflowURIs() {
+		StringList sl = new StringList();
+		List<URI> uris = localWorker.getPermittedWorkflowURIs();
+		if (uris != null)
+			for (URI uri : uris)
+				sl.string.add(uri.toString());
+		return sl;
+	}
+
+	private static final URI myExp = URI.create("http://www.myexperment.org/");
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public StringList setPermittedWorkflowURIs(StringList permitted) {
+		List<URI> uris = new ArrayList<>();
+		for (String uri : permitted.string)
+			try {
+				uris.add(myExp.resolve(uri));
+			} catch (Exception e) {
+				// Ignore
+			}
+		localWorker.setPermittedWorkflowURIs(uris);
+		return getPermittedWorkflowURIs();
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsPermittedWorkflowURIs() {
+		return opt("PUT");
+	}
+
+	// /////////////////////////////////////////////////////
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String getGenerateProvenance() {
+		return Boolean.toString(localWorker.getGenerateProvenance());
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public String setGenerateProvenance(String newValue) {
+		boolean b = Boolean.parseBoolean(newValue);
+		localWorker.setGenerateProvenance(b);
+		return Boolean.toString(localWorker.getGenerateProvenance());
+	}
+
+	@RolesAllowed(ADMIN)
+	@Override
+	public Response optionsGenerateProvenance() {
+		return opt("PUT");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
new file mode 100644
index 0000000..930fd75
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/admin/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the RESTful administration interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = ADMIN, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN),
+		@XmlNs(prefix = "ur", namespaceURI = UR),
+		@XmlNs(prefix = "ds", namespaceURI = XSIG) })
+package org.taverna.server.master.admin;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.UR;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.master.common.Namespaces.XSIG;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
new file mode 100644
index 0000000..1a89b8d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ContentTypes.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.api;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE;
+
+import java.util.List;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Variant;
+
+/**
+ * The content types supported at various points in the REST interface.
+ * 
+ * @author Donal Fellows
+ */
+public interface ContentTypes {
+	/** "application/zip" */
+	public static final MediaType APPLICATION_ZIP_TYPE = new MediaType(
+			"application", "zip");
+
+	/** "application/vnd.taverna.baclava+xml" */
+	public static final MediaType BACLAVA_MEDIA_TYPE = new MediaType(
+			"application", "vnd.taverna.baclava+xml");
+
+	/**
+	 * The media types that we are willing to serve up directories as. Note that
+	 * we <i>only</i> serve directories up as these.
+	 */
+	public static final List<Variant> DIRECTORY_VARIANTS = asList(new Variant(
+			APPLICATION_XML_TYPE, (String) null, "UTF-8"), new Variant(
+			APPLICATION_JSON_TYPE, (String) null, "UTF-8"), new Variant(
+			APPLICATION_ZIP_TYPE, (String) null, null));
+
+	/**
+	 * The baseline set of media types that we are willing to serve up files as.
+	 * Note that we <i>also</i> serve files up as their auto-detected media
+	 * type. In all cases, this means we just shovel the bytes (or characters,
+	 * in the case of <tt>text/*</tt> subtypes) back at the client.
+	 */
+	public static final List<Variant> INITIAL_FILE_VARIANTS = singletonList(new Variant(
+			APPLICATION_OCTET_STREAM_TYPE, (String) null, null));
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
new file mode 100644
index 0000000..8fa5c78
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/DirectoryBean.java
@@ -0,0 +1,16 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Description of properties supported by {@link DirectoryREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface DirectoryBean extends SupportAware {
+	void setFileUtils(FilenameUtils fileUtils);
+
+	TavernaServerDirectoryREST connect(TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
new file mode 100644
index 0000000..5ace6a3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/FeedBean.java
@@ -0,0 +1,13 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.InteractionFeed;
+import org.taverna.server.master.interaction.InteractionFeedSupport;
+
+/**
+ * Description of properties supported by {@link InteractionFeed}.
+ * 
+ * @author Donal Fellows
+ */
+public interface FeedBean {
+	void setInteractionFeedSupport(InteractionFeedSupport feed);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
new file mode 100644
index 0000000..eecea44
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/InputBean.java
@@ -0,0 +1,21 @@
+package org.taverna.server.master.api;
+
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * Description of properties supported by {@link InputREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface InputBean extends SupportAware {
+	TavernaServerInputREST connect(TavernaRun run, UriInfo ui);
+
+	void setCdBuilder(ContentsDescriptorBuilder cd);
+
+	void setFileUtils(FilenameUtils fn);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
new file mode 100644
index 0000000..5c480d4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenerPropertyBean.java
@@ -0,0 +1,15 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+
+/**
+ * Description of properties supported by {@link ListenerPropertyREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenerPropertyBean extends SupportAware {
+	TavernaServerListenersREST.Property connect(Listener listen,
+			TavernaRun run, String propertyName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
new file mode 100644
index 0000000..c02bf62
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ListenersBean.java
@@ -0,0 +1,13 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+
+/**
+ * Description of properties supported by {@link ListenersREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface ListenersBean extends SupportAware {
+	TavernaServerListenersREST connect(TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
new file mode 100644
index 0000000..6bc6058
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/ManagementModel.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.api;
+
+/**
+ * The model of the webapp's state Java Bean.
+ * 
+ * @author Donal Fellows
+ */
+public interface ManagementModel {
+	/**
+	 * @return whether we allow the creation of new workflow runs.
+	 */
+	boolean getAllowNewWorkflowRuns();
+
+	/**
+	 * @return whether we should log all workflows sent to us.
+	 */
+	boolean getLogIncomingWorkflows();
+
+	/**
+	 * @return whether outgoing exceptions should be logged before being
+	 *         converted to responses.
+	 */
+	boolean getLogOutgoingExceptions();
+
+	/**
+	 * @return the file that all usage records should be appended to, or
+	 *         <tt>null</tt> if they should be just dropped.
+	 */
+	String getUsageRecordLogFile();
+
+	/**
+	 * @param logIncomingWorkflows
+	 *            whether we should log all workflows sent to us.
+	 */
+	void setLogIncomingWorkflows(boolean logIncomingWorkflows);
+
+	/**
+	 * @param allowNewWorkflowRuns
+	 *            whether we allow the creation of new workflow runs.
+	 */
+	void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns);
+
+	/**
+	 * @param logOutgoingExceptions
+	 *            whether outgoing exceptions should be logged before being
+	 *            converted to responses.
+	 */
+	void setLogOutgoingExceptions(boolean logOutgoingExceptions);
+
+	/**
+	 * @param usageRecordLogFile
+	 *            the file that all usage records should be appended to, or
+	 *            <tt>null</tt> if they should be just dropped.
+	 */
+	void setUsageRecordLogFile(String usageRecordLogFile);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
new file mode 100644
index 0000000..9f80a12
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/OneListenerBean.java
@@ -0,0 +1,14 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+
+/**
+ * Description of properties supported by {@link InputREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface OneListenerBean {
+	TavernaServerListenerREST connect(Listener listen, TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
new file mode 100644
index 0000000..4903ea9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/RunBean.java
@@ -0,0 +1,17 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * Description of properties supported by {@link RunREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunBean extends SupportAware {
+	void setCdBuilder(ContentsDescriptorBuilder cdBuilder);
+
+	void setRun(TavernaRun run);
+
+	void setRunName(String runName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
new file mode 100644
index 0000000..04fbd6e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SecurityBean.java
@@ -0,0 +1,14 @@
+package org.taverna.server.master.api;
+
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+
+/**
+ * Description of properties supported by {@link RunSecurityREST}.
+ * 
+ * @author Donal Fellows
+ */
+public interface SecurityBean extends SupportAware {
+	TavernaServerSecurityREST connect(TavernaSecurityContext context, TavernaRun run);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
new file mode 100644
index 0000000..c632657
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/SupportAware.java
@@ -0,0 +1,21 @@
+package org.taverna.server.master.api;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.TavernaServerSupport;
+
+/**
+ * Indicates that this is a class that wants to be told by Spring about the
+ * main support bean.
+ * 
+ * @author Donal Fellows
+ */
+public interface SupportAware {
+	/**
+	 * How to tell the bean about the support bean.
+	 * 
+	 * @param support
+	 *            Reference to the support bean.
+	 */
+	@Required
+	void setSupport(TavernaServerSupport support);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
new file mode 100644
index 0000000..5a14fb6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/TavernaServerBean.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.api;
+
+import javax.annotation.Nonnull;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.ContentsDescriptorBuilder;
+import org.taverna.server.master.TavernaServerSupport;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.RunStore;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+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.soap.TavernaServerSOAP;
+import org.taverna.server.master.utils.FilenameUtils;
+
+/**
+ * The methods of the webapp that are accessed by beans other than itself or
+ * those which are told directly about it. This exists so that an AOP proxy can
+ * be installed around it.
+ * 
+ * @author Donal Fellows
+ */
+public interface TavernaServerBean extends TavernaServerSOAP, TavernaServerREST,
+		UriBuilderFactory {
+	/**
+	 * @param policy
+	 *            The policy being installed by Spring.
+	 */
+	@Required
+	void setPolicy(@Nonnull Policy policy);
+
+	/**
+	 * @param runStore
+	 *            The run store being installed by Spring.
+	 */
+	@Required
+	void setRunStore(@Nonnull RunStore runStore);
+
+	/**
+	 * @param converter
+	 *            The filename converter being installed by Spring.
+	 */
+	@Required
+	void setFileUtils(@Nonnull FilenameUtils converter);
+
+	/**
+	 * @param cdBuilder
+	 *            The contents descriptor builder being installed by Spring.
+	 */
+	@Required
+	void setContentsDescriptorBuilder(
+			@Nonnull ContentsDescriptorBuilder cdBuilder);
+
+	/**
+	 * @param notificationEngine
+	 *            The notification engine being installed by Spring.
+	 */
+	@Required
+	void setNotificationEngine(@Nonnull NotificationEngine notificationEngine);
+
+	/**
+	 * @param support
+	 *            The support bean being installed by Spring.
+	 */
+	@Required
+	void setSupport(@Nonnull TavernaServerSupport support);
+
+	/**
+	 * @param eventSource
+	 *            The event source bean being installed by Spring.
+	 */
+	@Required
+	void setEventSource(@Nonnull EventDAO eventSource);
+
+	/**
+	 * The nastier parts of security initialisation in SOAP calls, which we want
+	 * to go away.
+	 * 
+	 * @param context
+	 *            The context to configure.
+	 * @return True if we did <i>not</i> initialise things.
+	 */
+	boolean initObsoleteSOAPSecurity(@Nonnull TavernaSecurityContext context);
+
+	/**
+	 * The nastier parts of security initialisation in REST calls, which we want
+	 * to go away.
+	 * 
+	 * @param context
+	 *            The context to configure.
+	 * @return True if we did <i>not</i> initialise things.
+	 */
+	boolean initObsoleteRESTSecurity(@Nonnull TavernaSecurityContext context);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
new file mode 100644
index 0000000..fe76a09
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/api/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * API <tt>interface</tt>s for the main service classes.
+ * 
+ * @author Donal Fellows
+ */
+package org.taverna.server.master.api;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
new file mode 100644
index 0000000..034d489
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Capability.java
@@ -0,0 +1,22 @@
+package org.taverna.server.master.common;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Describes a single capability supported by Taverna Server's workflow
+ * execution core.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Capability")
+public class Capability {
+	@XmlAttribute
+	@XmlSchemaType(name = "anyURI")
+	public URI capability;
+	@XmlAttribute
+	public String version;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
new file mode 100644
index 0000000..5c16e79
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Credential.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.security.Key;
+import java.security.cert.Certificate;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A description of a private credential. This description is characterised by a
+ * file visible to the workflow run that contains a particular key-pair.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "CredentialDescriptor")
+@XmlSeeAlso({ Credential.KeyPair.class, Credential.Password.class })
+@SuppressWarnings("serial")
+public abstract class Credential implements Serializable {
+	/** The location of this descriptor in the REST world. */
+	@XmlAttribute(namespace = XLINK)
+	public String href;
+	/**
+	 * The location of this descriptor in the SOAP world. Must match corrected
+	 * with the {@link #href} field.
+	 */
+	@XmlTransient
+	public String id;
+	/**
+	 * The service URI to use this credential with. If omitted, this represents
+	 * the <i>default</i> credential to use.
+	 */
+	@XmlElement
+	@XmlSchemaType(name = "anyURI")
+	public URI serviceURI;
+	/** The key extracted from the keystore. */
+	public transient Key loadedKey;
+	/** The trust chain of the key extracted from the keystore. */
+	public transient Certificate[] loadedTrustChain;
+
+	@Override
+	public int hashCode() {
+		return id.hashCode();
+	}
+
+	@Override
+	public final boolean equals(Object o) {
+		if (o == null || !(o instanceof Credential))
+			return false;
+		return equals((Credential) o);
+	}
+
+	protected boolean equals(@Nonnull Credential c) {
+		return id.equals(c.id);
+	}
+
+	/**
+	 * A description of a credential that is a public/private key-pair in some
+	 * kind of key store.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "keypair")
+	@XmlType(name = "KeyPairCredential")
+	public static class KeyPair extends Credential {
+		/** The name of the credential within its store, i.e., it's alias. */
+		@XmlElement(required = true)
+		public String credentialName;
+		/**
+		 * The keystore file containing the credential. This is resolved with
+		 * respect to the workflow run working directory.
+		 */
+		@XmlElement
+		public String credentialFile;
+		/**
+		 * The type of keystore file. Defaults to <tt>JKS</tt> if unspecified.
+		 */
+		@XmlElement
+		public String fileType;
+		/**
+		 * The password used to unlock the keystore file. It is assumed that the
+		 * same password is used for unlocking the credential within, or that
+		 * the inner password is empty.
+		 */
+		@XmlElement
+		public String unlockPassword;
+		/**
+		 * The encoded serialized keystore containing the credential.
+		 */
+		@XmlElement
+		public byte[] credentialBytes;
+
+		@Override
+		public String toString() {
+			return "keypair(id=" + id + ")";
+		}
+	}
+
+	/**
+	 * A description of a credential that is a username and password.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "userpass")
+	@XmlType(name = "PasswordCredential")
+	public static class Password extends Credential {
+		@XmlElement(required = true)
+		public String username;
+		@XmlElement(required = true)
+		public String password;
+
+		@Override
+		public String toString() {
+			return "userpass(id=" + id + ")";
+		}
+	}
+
+	/**
+	 * A credential that is just used for deleting credentials by ID. Cannot be
+	 * marshalled as XML.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class Dummy extends Credential {
+		public Dummy(String id) {
+			this.id = id;
+		}
+
+		@Override
+		public String toString() {
+			return "dummy(id=" + id + ")";
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
new file mode 100644
index 0000000..318ae4f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/DirEntryReference.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.net.URI;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.DirectoryEntry;
+
+/**
+ * A reference to something that is in a directory below the working directory
+ * of a workflow run, described using JAXB. Note that when creating an XML
+ * document containing one of these in a client, it is <i>not</i> necessary to
+ * supply any attribute.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "DirectoryEntry")
+@XmlSeeAlso( { DirEntryReference.DirectoryReference.class,
+		DirEntryReference.FileReference.class })
+public class DirEntryReference {
+	/** A link to the entry. Ignored on input. */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	/** The last, user-displayable part of the name. Ignored on input. */
+	@XmlAttribute
+	public String name;
+	/** The path of the entry. */
+	@XmlValue
+	public String path;
+
+	/**
+	 * Return the directory entry reference instance subclass suitable for the
+	 * given directory entry.
+	 * 
+	 * @param entry
+	 *            The entry to characterise.
+	 * @return An object that describes the directory entry.
+	 */
+	public static DirEntryReference newInstance(DirectoryEntry entry) {
+		return newInstance(null, entry);
+	}
+
+	/**
+	 * Return the directory entry reference instance subclass suitable for the
+	 * given directory entry.
+	 * 
+	 * @param ub
+	 *            Used for constructing URIs. The {@link #link} field is not
+	 *            filled in if this is <tt>null</tt>.
+	 * @param entry
+	 *            The entry to characterise.
+	 * @return An object that describes the directory entry.
+	 */
+	// Really returns a subclass, so cannot be constructor
+	public static DirEntryReference newInstance(UriBuilder ub,
+			DirectoryEntry entry) {
+		DirEntryReference de = (entry instanceof Directory) ? new DirectoryReference()
+				: new FileReference();
+		de.name = entry.getName();
+		String fullname = entry.getFullName();
+		de.path = fullname.startsWith("/") ? fullname.substring(1) : fullname;
+		if (ub != null)
+			de.link = ub.build(entry.getName());
+		return de;
+	}
+
+	/** A reference to a directory, done with JAXB. */
+	@XmlRootElement(name = "dir")
+	@XmlType(name = "DirectoryReference")
+	public static class DirectoryReference extends DirEntryReference {
+	}
+
+	/** A reference to a file, done with JAXB. */
+	@XmlRootElement(name = "file")
+	@XmlType(name = "FileReference")
+	public static class FileReference extends DirEntryReference {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
new file mode 100644
index 0000000..bb98d6d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/InputDescription.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A description of the inputs to a workflow, described using JAXB.
+ * 
+ * @author Donal Fellows
+ */
+@XmlRootElement(name = "inputConfiguration")
+@XmlType(name = "InputConfigurationDescription")
+public class InputDescription extends VersionedElement {
+	/**
+	 * The Baclava file handling the description of the elements. May be
+	 * omitted/<tt>null</tt>.
+	 */
+	@XmlElement(required = false)
+	public String baclavaFile;
+	/**
+	 * The port/value assignment.
+	 */
+	@XmlElement(nillable = false)
+	public List<Port> port = new ArrayList<>();
+
+	/**
+	 * Make a blank input description.
+	 */
+	public InputDescription() {
+	}
+
+	/**
+	 * Make an input description suitable for the given workflow run.
+	 * 
+	 * @param run
+	 */
+	public InputDescription(TavernaRun run) {
+		super(true);
+		baclavaFile = run.getInputBaclavaFile();
+		if (baclavaFile == null)
+			for (Input i : run.getInputs())
+				port.add(new Port(i));
+	}
+
+	/**
+	 * The type of a single port description.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "PortConfigurationDescription")
+	public static class Port {
+		/**
+		 * The name of this port.
+		 */
+		@XmlAttribute(name = "portName", required = true)
+		public String name;
+		/**
+		 * The file assigned to this port.
+		 */
+		@XmlAttribute(name = "portFile", required = false)
+		public String file;
+		/**
+		 * The file assigned to this port.
+		 */
+		@XmlAttribute(name = "listDelimiter", required = false)
+		public String delimiter;
+		/**
+		 * The value assigned to this port.
+		 */
+		@XmlValue
+		public String value;
+
+		/**
+		 * Make a blank port description.
+		 */
+		public Port() {
+		}
+
+		/**
+		 * Make a port description suitable for the given input.
+		 * 
+		 * @param input
+		 */
+		public Port(Input input) {
+			name = input.getName();
+			if (input.getFile() != null) {
+				file = input.getFile();
+				value = "";
+			} else {
+				file = null;
+				value = input.getValue();
+			}
+			delimiter = input.getDelimiter();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
new file mode 100644
index 0000000..1311272
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Namespaces.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+/**
+ * A convenient place to keep the names of URIs so that they can be got right
+ * <i>once</i>.
+ * 
+ * @author Donal Fellows
+ */
+public interface Namespaces {
+	/**
+	 * The XLink specification's namespace name.
+	 */
+	public static final String XLINK = "http://www.w3.org/1999/xlink";
+	/**
+	 * The XML Digital Signature specification's namespace name.
+	 */
+	public static final String XSIG = "http://www.w3.org/2000/09/xmldsig#";
+	/**
+	 * The Usage Record specification's namespace name.
+	 */
+	public static final String UR = "http://schema.ogf.org/urf/2003/09/urf";
+	/**
+	 * The T2flow document format's namespace name.
+	 */
+	public static final String T2FLOW = "http://taverna.sf.net/2008/xml/t2flow";
+	/**
+	 * The namespace for the server.
+	 */
+	public static final String SERVER = "http://ns.taverna.org.uk/2010/xml/server/";
+	public static final String SERVER_REST = SERVER + "rest/";
+	public static final String SERVER_SOAP = SERVER + "soap/";
+	public static final String FEED = SERVER + "feed/";
+	public static final String ADMIN = SERVER + "admin/";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
new file mode 100644
index 0000000..258bfd0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/common/Permission.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.common;
+
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Description of a permission to access a particular workflow run. Note that
+ * users always have full access to their own runs, as does any user with the "
+ * <tt>{@value org.taverna.server.master.common.Roles#ADMIN}</tt>" ability.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "Permission")
+@XmlEnum
+public enum Permission {
+	/** Indicates that a user cannot see the workflow run at all. */
+	@XmlEnumValue("none")
+	None,
+	/**
+	 * Indicates that a user can see the workflow run and its contents, but
+	 * can't modify anything.
+	 */
+	@XmlEnumValue("read")
+	Read,
+	/**
+	 * Indicates that a user can update most aspects of a workflow, but cannot
+	 * work with either its security features or its lifetime.
+	 */
+	@XmlEnumValue("update")
+	Update,
+	/**
+	 * Indicates that a user can update almost all aspects of a workflow, with
+	 * only its security features being shrouded.
+	 */
+	@XmlEnumValue("destroy")
+	Destroy
+}
\ No newline at end of file


[27/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png b/server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png
deleted file mode 100644
index c664c51..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_diagonals-small_25_c5ddfc_40x40.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png b/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png
deleted file mode 100644
index 6aed97a..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_20_e69700_40x40.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png b/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png
deleted file mode 100644
index 43ba34e..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_22_1484e6_40x40.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png b/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png
deleted file mode 100644
index 68306d1..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_diagonals-thick_26_2293f7_40x40.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png b/server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png
deleted file mode 100644
index f567c28..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_flat_0_e69700_40x100.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png b/server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png
deleted file mode 100644
index 5c5494f..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_flat_0_e6b900_40x100.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png b/server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png
deleted file mode 100644
index 9a46d19..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_highlight-soft_100_f9f9f9_1x100.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png b/server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png
deleted file mode 100644
index f811f30..0000000
Binary files a/server-webapp/src/main/resources/static/ui-bg_inset-hard_100_eeeeee_1x100.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png b/server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png
deleted file mode 100644
index 755fe99..0000000
Binary files a/server-webapp/src/main/resources/static/ui-icons_0a82eb_256x240.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png b/server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png
deleted file mode 100644
index 98705f9..0000000
Binary files a/server-webapp/src/main/resources/static/ui-icons_0b54d5_256x240.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png b/server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png
deleted file mode 100644
index 3f67eca..0000000
Binary files a/server-webapp/src/main/resources/static/ui-icons_5fa5e3_256x240.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png b/server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png
deleted file mode 100644
index de76ce2..0000000
Binary files a/server-webapp/src/main/resources/static/ui-icons_fcdd4a_256x240.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png b/server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png
deleted file mode 100644
index 42f8f99..0000000
Binary files a/server-webapp/src/main/resources/static/ui-icons_ffffff_256x240.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/version.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/version.properties b/server-webapp/src/main/resources/version.properties
deleted file mode 100644
index 7ddb7d3..0000000
--- a/server-webapp/src/main/resources/version.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-# What is the version of the server? Bind this in automatically.
-tavernaserver.version=${project.version}
-tavernaserver.revision.describe=${git.commit.id.describe}
-tavernaserver.branch=${git.branch}
-tavernaserver.timestamp=${git.build.time}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/welcome.html
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/welcome.html b/server-webapp/src/main/resources/welcome.html
deleted file mode 100644
index f80da4a..0000000
--- a/server-webapp/src/main/resources/welcome.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
-<title>Taverna Server %{VERSION}</title>
-</head>
-<body>
-<h1>Taverna Server %{VERSION}</h1>
-<div style="text-align;center">
-	<p>
-		<i>Note that this is a pre-release version. Significant known
-			issues remain open and it is not guaranteed that the service API
-			will be stable.</i>
-	</p>
-</div>
-<p>For a full list of operations, see the <a
-    href="%{BASEURL}/services">service listing</a> generated by Apache
-CXF, which indicates where to access the WSDL and WADL descriptions of
-the T2Server interface.</p>
-<p>What follows below is a simple guide to using the server. It does
-<i>not</i> cover all the features; a much more extensive guide is available on
-<a href="http://www.mygrid.org.uk/dev/wiki/display/taverna/Taverna+Server+2.4"
->the myGrid website</a>.</p>
-<h2>5 Minute Guide to Using the REST API</h2>
-<p>Taverna Server %{VERSION} supports both REST and SOAP APIs; you may use either API
-to access the service and any of the workflow runs hosted by the service. This
-simple guide just discusses the REST API.</p>
-<ol>
-  <li>
-  <p>The client starts by creating a workflow run. This is done by POSTing a
-  T2flow document to the service at the address <tt>%{BASEURL}/rest/runs</tt>
-  with the content type <tt>application/vnd.taverna.t2flow+xml</tt>.</p>
-  <p>The result of the POST is an <tt>HTTP 201 Created</tt> that gives the
-  location of the created run (in a <tt>Location</tt> header),
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b></tt> (where <tt><b>UUID</b></tt> is a
-  unique string that identifies the particular run; this is also the name of
-  the run that you would use in the SOAP interface). Note that the run is not
-  yet actually doing anything.</p>
-  </li>
-  <li>
-  <p>Next, you need to set up the inputs to the workflow ports. To set the
-  input port, <tt><b>FOO</b></tt>, to have the value <tt><b>BAR</b></tt>, you
-  would PUT a message like this to the URI
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/input/input/<b>FOO</b></tt>
-  </p>
-  <blockquote><pre>&lt;t2sr:runInput xmlns:t2sr=&quot;http://ns.taverna.org.uk/2010/xml/server/rest/&quot;&gt;
-    &lt;t2sr:value&gt;<b>BAR</b>&lt;/t2sr:value&gt;
-&lt;/t2sr:runInput&gt;</pre></blockquote>
-  </li>
-  <li>
-  <p>Now you can start the file running. This is done by using a PUT to set
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/status</tt> to the plain text value
-  <tt>Operating</tt>.</p>
-  </li>
-  <li>
-  <p>Now you need to poll, waiting for the workflow to finish. To discover the
-  state of a run, you can (at any time) do a GET on
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/status</tt>; when the workflow has
-  finished executing, this will return <tt>Finished</tt> instead of
-  <tt>Operating</tt> (or <tt>Initialized</tt>, the starting state).</p>
-  </li>
-  <li>
-  <p>Every workflow run has an expiry time, after which it will be destroyed
-  and all resources (i.e., local files) associated with it cleaned up. By
-  default in this release, this is 20 minutes after initial creation. To see
-  when a particular run is scheduled to be disposed of, do a GET on
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/expiry</tt>; you may set the time when
-  the run is disposed of by PUTting a new time to that same URI. Note that
-  this includes not just the time when the workflow is executing, but also
-  when the input files are being created beforehand and when the results are
-  being downloaded afterwards; you are advised to make your clients regularly
-  advance the expiry time while the run is in use.</p>
-  </li>
-  <li>
-  <p>The outputs from the workflow are files created in the <tt>out</tt>
-  subdirectory of the run's working directory. The contents of the
-  subdirectory can be read by doing a GET on
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out</tt> which will return an XML
-  document describing the contents of the directory, with links to each of the
-  files within it. Doing a GET on those links will retrieve the actual created
-  files (as uninterpreted binary data).</p>
-  <p>Thus, if a single output <tt><b>FOO.OUT</b></tt> was produced from the
-  workflow, it would be written to the file that can be retrieved from
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out/<b>FOO.OUT</b></tt> and the
-  result of the GET on <tt>%{BASEURL}/rest/runs/<b>UUID</b>/wd/out</tt> would
-  look something like this:</p>
-  <blockquote><pre>&lt;t2sr:directoryContents xmlns:xlink="http://www.w3.org/1999/xlink"
-        xmlns:t2sr="http://ns.taverna.org.uk/2010/xml/server/rest"
-        xmlns:t2s="http://ns.taverna.org.uk/2010/xml/server/"&gt;
-    &lt;t2s:file xlink:href="%{BASEURL}/rest/runs/<b>UUID</b>/wd/out/<b>FOO.OUT</b>"
-            t2sr:name="<b>FOO.OUT</b>"&gt;out/<b>FOO.OUT</b>&lt;/t2s:file&gt;
-&lt;/t2sr:directoryContents&gt;</pre></blockquote>
-  </li>
-  <li>
-  <p>The standard output and standard error from the T2 Command Line Executor
-  subprocess can be read via properties of the special I/O listener. To do
-  that, do a GET on
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b>/listeners/io/properties/<b>stdout</b></tt>
-  (or <tt>.../<b>stderr</b></tt>). Once the subprocess has finished executing,
-  the I/O listener will provide a third property containing the exit code of
-  the subprocess, called <tt>exitcode</tt>.</p> <p>Note that the supported set
-  of listeners and properties will be subject to change in future versions of
-  the server, and should not be relied upon.</p>
-  </li>
-  <li>
-  <p>Once you have finished, destroy the run by doing a DELETE on
-  <tt>%{BASEURL}/rest/runs/<b>UUID</b></tt>. Once you have done that, none of
-  the resources associated with the run (including both input and output
-  files) will exist any more. If the run is still executing, this will also
-  cause it to be stopped.</p>
-  </li>
-</ol>
-<p>All operations described above have equivalents in the
-<a href="%{BASEURL}/soap?wsdl">SOAP service interface</a>.</p>
-
-<div>
-<hr>
-<p><small>Copyright &copy; 2010&ndash;2014. The University of Manchester.</small></p>
-<p><small>Software Release ID: ${project.version} (commit: ${git.branch})</small></p>
-</div>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/META-INF/MANIFEST.MF b/server-webapp/src/main/webapp/META-INF/MANIFEST.MF
deleted file mode 100644
index 5e94951..0000000
--- a/server-webapp/src/main/webapp/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Class-Path: 
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger b/server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
deleted file mode 100644
index 4fd9372..0000000
--- a/server-webapp/src/main/webapp/META-INF/cxf/org.apache.cxf.Logger
+++ /dev/null
@@ -1 +0,0 @@
-org.apache.cxf.common.logging.Log4jLogger

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/META-INF/persistence.xml b/server-webapp/src/main/webapp/META-INF/persistence.xml
deleted file mode 100644
index afd640a..0000000
--- a/server-webapp/src/main/webapp/META-INF/persistence.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<persistence version="1.0"
-	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd ">
-	<persistence-unit name="TavernaServer">
-		<class>org.taverna.server.master.WebappState</class>
-		<class>org.taverna.server.master.identity.User</class>
-		<class>org.taverna.server.master.localworker.PersistedState</class>
-		<class>org.taverna.server.master.notification.atom.Event</class>
-		<class>org.taverna.server.master.usage.UsageRecord</class>
-		<class>org.taverna.server.master.worker.RunConnection</class>
-		<exclude-unlisted-classes>true</exclude-unlisted-classes>
-	</persistence-unit>
-</persistence>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/beans.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/beans.xml b/server-webapp/src/main/webapp/WEB-INF/beans.xml
deleted file mode 100644
index 73990a7..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/beans.xml
+++ /dev/null
@@ -1,518 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
-	default-lazy-init="false"
-	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
-		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-	<bean id="webapp" class="org.taverna.server.master.TavernaServer">
-		<property name="policy" ref="worker.policy" />
-		<property name="runStore" ref="worker.rundb" />
-		<property name="fileUtils" ref="fileUtils" />
-		<property name="contentsDescriptorBuilder" ref="contentsDescriptorBuilder" />
-		<property name="notificationEngine" ref="notificationFabric" />
-		<property name="support" ref="webapp.support" />
-		<property name="eventSource" ref="dispatch.atom" />
-		<property name="interactionFeed" value="${taverna.interaction.feed_path}" />
-		<lookup-method name="makeRunInterface" bean="run.coreView.prototype" />
-		<lookup-method name="getPolicyDescription" bean="webapp.policyView" />
-	</bean>
-
-	<bean id="webapp.support" class="org.taverna.server.master.TavernaServerSupport">
-		<property name="policy" ref="worker.policy" />
-		<property name="listenerFactory" ref="localworker.factory" />
-		<property name="runFactory" ref="localworker.factory" />
-		<property name="fileUtils" ref="fileUtils" />
-		<property name="runStore" ref="worker.rundb" />
-		<property name="stateModel" ref="webapp.state" />
-		<property name="idMapper" ref="IdentityMapper" />
-		<property name="invocationCounter" ref="webapp.invocationCounter" />
-		<property name="webapp" ref="webapp" />
-		<property name="contentTypeMap">
-			<map key-type="java.lang.String" value-type="java.lang.String">
-				<description>Maps suffixes (post '.') to content types.</description>
-				<entry key="baclava" value="application/vnd.taverna.baclava+xml" />
-				<entry key="robundle.zip" value="application/vnd.wf4ever.robundle+zip" />
-			</map>
-		</property>
-		<property name="capabilitySource" ref="capabilities" />
-	</bean>
-
-	<bean id="capabilities" class="org.taverna.server.master.utils.CapabilityLister" />
-
-	<bean id="webapp.policyView" class="org.taverna.server.master.PolicyREST">
-		<property name="support" ref="webapp.support" />
-		<property name="policy" ref="worker.policy" />
-		<property name="listenerFactory" ref="localworker.factory" />
-		<property name="notificationEngine" ref="notificationFabric" />
-	</bean>
-
-	<bean id="contentsDescriptorBuilder" class="org.taverna.server.master.ContentsDescriptorBuilder">
-		<property name="uriBuilderFactory" ref="webapp" />
-		<property name="fileUtils" ref="fileUtils" />
-	</bean>
-
-	<bean id="webapp.state" class="org.taverna.server.master.ManagementState">
-		<description>The initial state of the webapp.</description>
-		<property name="logIncomingWorkflows" value="${default.logworkflows}" />
-		<property name="allowNewWorkflowRuns" value="${default.permitsubmit}" />
-		<property name="logOutgoingExceptions" value="${default.logexceptions}" />
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<property name="self" ref="webapp.state" />
-	</bean>
-
-	<bean id="webapp.invocationCounter" class="org.taverna.server.master.utils.InvocationCounter" />
-	<bean id="webapp.perfLogger" class="org.taverna.server.master.utils.CallTimeLogger">
-		<property name="threshold" value="${calltime.logthreshold:4000000}" />
-	</bean>
-
-	<bean id="run.coreView.prototype" scope="prototype"
-		class="org.taverna.server.master.RunREST">
-		<property name="support" ref="webapp.support" />
-		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
-		<lookup-method name="makeSecurityInterface" bean="run.securityView.prototype" />
-		<lookup-method name="makeInputInterface" bean="run.inputView.prototype" />
-		<lookup-method name="makeListenersInterface" bean="run.listenersView.prototype" />
-		<lookup-method name="makeDirectoryInterface" bean="run.directoryView.prototype" />
-		<lookup-method name="makeInteractionFeed" bean="run.interactionFeed.prototype" />
-	</bean>
-
-	<bean id="run.directoryView.prototype" scope="prototype"
-		class="org.taverna.server.master.DirectoryREST">
-		<property name="support" ref="webapp.support" />
-		<property name="fileUtils" ref="fileUtils" />
-	</bean>
-
-	<bean id="run.listenersView.prototype" scope="prototype"
-		class="org.taverna.server.master.ListenersREST">
-		<property name="support" ref="webapp.support" />
-		<lookup-method name="makeListenerInterface" bean="run.singleListenerView.prototype" />
-	</bean>
-
-	<bean id="run.singleListenerView.prototype" scope="prototype"
-		class="org.taverna.server.master.SingleListenerREST">
-		<lookup-method name="makePropertyInterface" bean="run.propertyView.prototype" />
-	</bean>
-
-	<bean id="run.propertyView.prototype" scope="prototype"
-		class="org.taverna.server.master.ListenerPropertyREST">
-		<property name="support" ref="webapp.support" />
-	</bean>
-
-	<bean id="run.inputView.prototype" scope="prototype"
-		class="org.taverna.server.master.InputREST">
-		<property name="support" ref="webapp.support" />
-		<property name="cdBuilder" ref="contentsDescriptorBuilder" />
-		<property name="fileUtils" ref="fileUtils" />
-	</bean>
-
-	<bean id="run.securityView.prototype" scope="prototype"
-		class="org.taverna.server.master.RunSecurityREST">
-		<property name="support" ref="webapp.support" />
-	</bean>
-
-	<bean id="run.interactionFeed.prototype" scope="prototype"
-		class="org.taverna.server.master.InteractionFeed">
-		<property name="interactionFeedSupport" ref="interactionFeed" />
-	</bean>
-
-	<bean id="feed" class="org.taverna.server.master.notification.atom.AtomFeed">
-		<property name="eventSource" ref="dispatch.atom" />
-		<property name="support" ref="webapp.support" />
-		<property name="feedLanguage" value="${atom.language}" />
-		<property name="abdera" ref="abdera" />
-	</bean>
-
-	<bean id="admin" class="org.taverna.server.master.admin.AdminBean">
-		<property name="adminHtmlFile" value="/admin.html" />
-		<property name="counter" ref="webapp.invocationCounter" />
-		<property name="factory" ref="localworker.factory" />
-		<property name="localWorkerModel" ref="localworker.state" />
-		<property name="runDB" ref="worker.rundb" />
-		<property name="state" ref="webapp.state" />
-		<property name="usageRecords" ref="usageRecordSink" />
-		<property name="userStore" ref="userStore" />
-	</bean>
-
-	<bean id="IdentityMapper" class="org.taverna.server.master.identity.CompositeIDMapper">
-		<property name="identityMappers">
-			<list>
-				<bean id="AuthorityBased"
-					class="org.taverna.server.master.identity.AuthorityDerivedIDMapper">
-					<description>Derives the local user identity to use for execution
-						from the LOCALUSER_* Spring Security authority. Thus, if the user
-						has &quot;LOCALUSER_foo&quot;, they will be executing as the local
-						user id &quot;foo&quot;.</description>
-				</bean>
-				<bean id="SelfAccess"
-					class="org.taverna.server.master.identity.WorkflowInternalAuthProvider.WorkflowSelfIDMapper">
-					<description>Handles the case where a workflow is accessing itself for
-						the purpose of publishing interactions.</description>
-					<property name="runStore" ref="worker.rundb" />
-				</bean>
-				<bean id="Extracting" class="org.taverna.server.master.identity.NameIDMapper">
-					<description>An alternate mechanism for mapping users. This tries
-						to use an RE to extract the user name from the principal name.
-					</description>
-					<property name="regexp" value="${localusernameregexp}">
-						<description>An optional regexp to extract the local user name
-							from the principal's string description. The first capturing
-							group will be the result of the mapping operation.
-						</description>
-					</property>
-				</bean>
-				<bean id="Constant" class="org.taverna.server.master.identity.ConstantIDMapper">
-					<description>How to map web principals to local users. This one
-						maps everyone to the same user, "taverna".
-					</description>
-					<property name="constantId" value="${default.localusername}" />
-				</bean>
-			</list>
-		</property>
-	</bean>
-
-	<bean id="passwordEncoder"
-		class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
-	<bean class="org.taverna.server.master.identity.UserStore" id="userStore">
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<property name="baselineUserProperties">
-			<util:properties location="/WEB-INF/security/users.properties" />
-		</property>
-		<property name="defaultLocalUser" value="${default.localusername}" />
-		<property name="encoder" ref="passwordEncoder" />
-	</bean>
-
-	<!-- <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 
-		<property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> 
-		<props> <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop> 
-		<prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> <property 
-		name="annotatedClasses"> <list> </list> </property> </bean> -->
-	<bean id="pmb" class="org.taverna.server.master.utils.JDOSupport.PersistenceManagerBuilder">
-		<property name="persistenceManagerFactory">
-			<bean id="pmf" class="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"
-				destroy-method="close">
-				<property name="connectionFactory" ref="dataSource" />
-				<property name="nontransactionalRead" value="true" />
-				<property name="persistenceProperties">
-					<props>
-						<prop key="datanucleus.storeManagerType">rdbms</prop>
-						<prop key="datanucleus.autoCreateTables">true</prop>
-						<prop key="datanucleus.autoCreateTables">true</prop>
-						<prop key="datanucleus.validateTables">true</prop>
-						<prop key="datanucleus.autoCreateColumns">true</prop>
-						<prop key="datanucleus.autoCreateConstraints">true</prop>
-						<prop key="datanucleus.validateConstraints">true</prop>
-						<prop key="datanucleus.autoCreateSchema">true</prop>
-						<prop key="datanucleus.PersistenceUnitName">TavernaServer</prop>
-						<prop key="datanucleus.rdbms.datastoreAdapterClassName"
-							>org.taverna.server.master.utils.LoggingDerbyAdapter</prop>
-					</props>
-				</property>
-			</bean>
-		</property>
-	</bean>
-	<bean id="transactionAspect"
-		class="org.taverna.server.master.utils.JDOSupport.TransactionAspect" />
-
-	<bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
-		<description>http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file</description>
-		<property name="targetObject" value="#{@systemProperties}" />
-		<property name="targetMethod" value="putAll" />
-		<property name="arguments">
-			<util:properties>
-				<prop key="derby.stream.error.field">org.taverna.server.master.utils.DerbyUtils.TO_LOG</prop>
-				<prop key="derby.stream.error.logSeverityLevel">30000</prop>
-			</util:properties>
-		</property>
-	</bean>
-	<!-- TODO: control the location of the database properly, or move to JNDI 
-		TODO: review whether what we are doing now is correct! -->
-	<bean id="dataSource" class="org.taverna.server.master.utils.WebappAwareDataSource">
-		<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
-		<property name="url"
-			value="jdbc:derby:directory:%{WEBAPPROOT}tavernaserver;create=true" />
-		<!-- Needed for Derby... -->
-		<property name="shutdownUrl"
-			value="jdbc:derby:directory:%{WEBAPPROOT}tavernaserver;shutdown=true" />
-		<property name="username" value="taverna" />
-		<property name="password" value="" />
-		<property name="contextualizer" ref="contextualizer" />
-	</bean>
-
-	<bean id="contextualizer" class="org.taverna.server.master.utils.Contextualizer" />
-
-	<bean id="usageRecordSink" class="org.taverna.server.master.usage.UsageRecordRecorder">
-		<property name="state" ref="webapp.state" />
-		<property name="contextualizer" ref="contextualizer" />
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<property name="self" ref="usageRecordSink" />
-		<property name="disableDB" value="${usage.disableDB}" />
-		<property name="logFile" value="${usage.logFile}" />
-	</bean>
-
-	<context:property-placeholder
-		ignore-unresolvable="true" order="2" properties-ref="default-factory-properties" />
-	<util:properties id="default-factory-properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.IdAwareForkRunFactory</prop>
-	</util:properties>
-
-	<!-- This bean configuration replaced with org.taverna.server.master.localworker.LocalWorkerFactory -->
-	<!-- <bean id="localworker.factory" scope="singleton" lazy-init="false" 
-		class="${backEndFactory}"> <description> The simple policy manager and factory 
-		for the baseline localworker case. </description> <property name="state" 
-		ref="localworker.state" /> <property name="runDB" ref="worker.rundb" 
-		/> -->
-	<!-- Handled by autowiring to make type-resilient. -->
-	<!-- <property name="idMapper" ref="IdentityMapper" /> -->
-	<!-- <property name="securityContextFactory" ref="worker.securityContext" 
-		/> <property name="usageRecordSink" ref="usageRecordSink" /> <property name="URProcessorPool" 
-		ref="URThreads" /> </bean> -->
-
-	<!-- <task:executor id="URThreads" pool-size="${pool.size}" /> -->
-
-	<bean id="worker.securityContext"
-		class="org.taverna.server.master.worker.SecurityContextFactory">
-		<property name="runDatabase" ref="worker.rundb" />
-		<property name="filenameConverter" ref="fileUtils" />
-		<property name="x500Utils" ref="x500Utils" />
-		<property name="httpRealm" value="${http.realmName}" />
-		<property name="uriSource" ref="webapp" />
-		<property name="certificateFetcher" ref="certificateChainFetcher" />
-		<property name="passwordIssuer" ref="passwordIssuer" />
-	</bean>
-
-	<bean id="passwordIssuer" class="org.taverna.server.master.worker.PasswordIssuer">
-		<!-- <property name="length" value="8" /> -->
-	</bean>
-
-	<bean id="certificateChainFetcher" class="org.taverna.server.master.utils.CertificateChainFetcher">
-		<property name="secure" value="${fetchCertificateChain}" />
-	</bean>
-
-	<bean id="localworker.state" class="org.taverna.server.master.localworker.LocalWorkerState"
-		scope="singleton" lazy-init="false">
-		<description>
-			The state of the simple factory for the identity-aware
-			local worker.
-		</description>
-		<property name="defaultLifetime" value="${default.lifetime}">
-			<description>How long the run lasts for by default, in seconds.
-			</description>
-		</property>
-		<property name="maxRuns" value="${default.runlimit}">
-			<description>The maximum simultaneous number of runs.</description>
-		</property>
-		<property name="operatingLimit" value="${default.operatinglimit}">
-			<description>
-				The maximum number of runs that are in the Operating state,
-				i.e., actually running with a process consuming resources.
-			</description>
-		</property>
-		<property name="extraArgs">
-			<description>Any extra arguments (memory control, etc.) to pass to
-				the spawned subprocesses.
-			</description>
-			<list>
-			</list>
-		</property>
-		<property name="waitSeconds" value="40">
-			<description>An upper bound (in seconds) on the time to wait for a
-				subprocess to start before failing it.
-			</description>
-		</property>
-		<property name="sleepMS" value="1000">
-			<description>The time to wait (in milliseconds) between polling for
-				the subprocess to complete its registration.
-			</description>
-		</property>
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<!-- <property name="javaBinary"> <description>The name of the java executable 
-			used to run the server worker. Defaults to the executable used to run the 
-			hosting environment.</description> </property> -->
-		<!-- <property name="serverWorkerJar"> <description>The full path to the 
-			executable JAR file containing the implementation of the server worker.</description> 
-			</property> -->
-		<!-- <property name="executeWorkflowScript"> <description>The full path 
-			to the executeworkflow.sh in either the Taverna 2 Workbench distribution 
-			or the Taverna 2 Command Line distribution.</description> </property> -->
-		<property name="self" ref="localworker.state" />
-		<property name="defaultExecuteWorkflowScript" value="${executeWorkflowScript:NONE}" />
-	</bean>
-
-	<bean id="worker.policy" class="org.taverna.server.master.worker.PolicyImpl">
-		<description>
-			The implementation of the access control policy supported
-			by the localworker run engine.
-		</description>
-		<property name="limits" ref="localworker.state" />
-		<property name="runDB" ref="worker.rundb" />
-	</bean>
-	<bean id="worker.rundb" class="org.taverna.server.master.worker.RunDatabase">
-		<property name="notifier" ref="worker.notifier" />
-		<property name="typeNotifiers">
-			<list>
-				<ref bean="cn.email" />
-				<ref bean="cn.sms" />
-				<ref bean="cn.twitter" />
-				<!-- <ref bean="cn.xmpp"/> -->
-			</list>
-		</property>
-		<property name="notificationEngine" ref="notificationFabric" />
-		<property name="dao" ref="worker.runDAO" />
-	</bean>
-	<bean id="cn.email"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
-		<property name="name" value="email" />
-		<property name="subject" value="Workflow run finished executing" />
-		<property name="velocityEngine" ref="velocity" />
-		<property name="uriBuilderFactory" ref="webapp" />
-	</bean>
-	<bean id="cn.sms"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
-		<property name="name" value="sms" />
-		<property name="subject" value="Run finished" />
-		<property name="velocityEngine" ref="velocity" />
-		<property name="uriBuilderFactory" ref="webapp" />
-	</bean>
-	<bean id="cn.twitter"
-		class="org.taverna.server.master.worker.VelocityCompletionNotifier">
-		<property name="name" value="twitter" />
-		<property name="subject" value="Run finished" />
-		<property name="velocityEngine" ref="velocity" />
-		<property name="uriBuilderFactory" ref="webapp" />
-	</bean>
-	
-	<bean id="worker.runDAO" class="org.taverna.server.master.worker.RunDatabaseDAO">
-		<description>
-			The implementation of the catalog of workflow runs
-			supported by the localworker run engine.
-		</description>
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<property name="facade" ref="worker.rundb" />
-	</bean>
-	<task:scheduled-tasks scheduler="taskScheduler">
-		<task:scheduled ref="worker.rundb" method="cleanNow"
-			fixed-delay="${purge.interval}" />
-		<task:scheduled ref="worker.rundb" method="checkForFinishNow"
-			fixed-delay="${finish.interval}" />
-		<task:scheduled ref="dispatch.atom" method="deleteExpiredEvents"
-			fixed-delay="${atom.cleaninterval}" />
-	</task:scheduled-tasks>
-
-	<bean id="notificationFabric"
-		class="org.taverna.server.master.notification.NotificationEngine">
-		<property name="dispatchers">
-			<list>
-				<ref bean="dispatch.email" />
-				<ref bean="dispatch.twitter" />
-				<ref bean="dispatch.xmpp" />
-				<ref bean="dispatch.sms" />
-			</list>
-		</property>
-		<property name="universalDispatchers">
-			<list>
-				<ref bean="dispatch.atom" />
-			</list>
-		</property>
-	</bean>
-
-	<bean id="dispatch.email" class="org.taverna.server.master.notification.EmailDispatcher">
-		<property name="from" value="${email.from}" />
-		<property name="messageContentType" value="${email.type}" />
-		<property name="cooldownSeconds" value="${message.cooldown}" />
-		<property name="smtpHost" value="${email.host}" />
-		<property name="sender">
-			<bean class="org.springframework.mail.javamail.JavaMailSenderImpl"
-				id="javamail">
-				<property name="host" value="${email.host}" />
-			</bean>
-		</property>
-	</bean>
-	<bean id="dispatch.twitter"
-		class="org.taverna.server.master.notification.TwitterDispatcher">
-		<property name="cooldownSeconds" value="${message.cooldown}" />
-		<property name="accessToken" value="${twitter.oauth.accessToken}" />
-		<property name="accessSecret" value="${twitter.oauth.accessTokenSecret}" />
-	</bean>
-	<bean id="dispatch.xmpp" class="org.taverna.server.master.notification.JabberDispatcher">
-		<property name="resource" value="${xmpp.resource}" />
-		<property name="host" value="${xmpp.service}" />
-		<property name="username" value="${xmpp.user}" />
-		<property name="password" value="${xmpp.password}" />
-	</bean>
-	<bean id="dispatch.sms" class="org.taverna.server.master.notification.SMSDispatcher">
-		<property name="usernameField" value="${sms.userfield}" />
-		<property name="passwordField" value="${sms.passfield}" />
-		<property name="destinationField" value="${sms.destfield}" />
-		<property name="messageField" value="${sms.msgfield}" />
-		<property name="cooldownSeconds" value="${message.cooldown}" />
-	</bean>
-
-	<bean id="dispatch.atom" class="org.taverna.server.master.notification.atom.EventDAO">
-		<property name="expiryAgeDays" value="${atom.lifespan}" />
-		<property name="persistenceManagerBuilder" ref="pmb" />
-		<property name="uriBuilderFactory" ref="feed" />
-		<property name="self" ref="dispatch.atom" />
-	</bean>
-
-	<bean id="worker.notifier"
-		class="org.taverna.server.master.worker.SimpleFormattedCompletionNotifier">
-		<property name="subject" value="${message.termination.subject}" />
-		<property name="messageFormat" value="${message.termination.body}" />
-		<property name="name" value="fallback"/>
-	</bean>
-
-	<bean id="fileUtils" class="org.taverna.server.master.utils.FilenameUtils" />
-	<bean id="x500Utils" class="org.taverna.server.master.utils.X500Utils" />
-	<task:scheduler id="taskScheduler" pool-size="${pool.size}" />
-
-	<bean class="org.taverna.server.master.utils.JCECheck" id="JCECheck" />
-
-	<bean class="org.taverna.server.master.interaction.InteractionFeedSupport"
-		id="interactionFeed" scope="singleton">
-		<property name="abdera" ref="abdera" />
-		<property name="support" ref="webapp.support" />
-		<property name="uriBuilder" ref="webapp" />
-		<property name="utils" ref="fileUtils" />
-	</bean>
-	<bean class="org.taverna.server.master.rest.handler.FeedHandler" id="atomFeedHandler">
-		<property name="abdera" ref="abdera" />
-	</bean>
-	<bean class="org.taverna.server.master.rest.handler.EntryHandler" id="atomEntryHandler">
-		<property name="abdera" ref="abdera" />
-	</bean>
-
-	<bean id="authProvider" class="org.taverna.server.master.identity.StrippedDownAuthProvider">
-		<property name="passwordEncoder" ref="passwordEncoder" />
-		<property name="userDetailsService">
-			<bean class="org.taverna.server.master.identity.UserStore.CachedUserStore">
-				<property name="realStore" ref="userStore" />
-			</bean>
-		</property>
-	</bean>
-	<bean id="workflowInternalAuthProvder"
-		class="org.taverna.server.master.identity.WorkflowInternalAuthProvider">
-		<property name="dao" ref="worker.runDAO" />
-		<property name="cacheBound" value="${default.runlimit}" />
-	</bean>
-	<bean id="velocity" class="org.apache.velocity.app.VelocityEngine"
-		init-method="init" lazy-init="false">
-		<constructor-arg>
-			<props>
-				<prop key="input.encoding">UTF-8</prop>
-				<prop key="output.encoding">UTF-8</prop>
-				<prop key="runtime.log.logsystem.class">org.apache.velocity.runtime.log.Log4JLogChute</prop>
-				<prop key="runtime.log.logsystem.log4j.logger">org.taverna.server.master.worker.VelocityCompletionNotifier</prop>
-				<prop key="resource.loader">class</prop>
-				<prop key="class.resource.loader.description">Velocity Classpath Resource Loader</prop>
-				<prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
-			</props>
-		</constructor-arg>
-	</bean>
-	<bean id="abdera" class="org.apache.abdera.Abdera"/>
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/insecure.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/insecure.xml b/server-webapp/src/main/webapp/WEB-INF/insecure.xml
deleted file mode 100644
index 92c0b03..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/insecure.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:security="http://www.springframework.org/schema/security"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:util="http://www.springframework.org/schema/util"
-	xsi:schemaLocation="http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
-		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
-
-	<description>
-		The Taverna Server bean, plus supporting configuration.
-		THIS IS AN INSECURE CONFIGURATION!
-	</description>
-
-	<import resource="webappBeans.xml" />
-
-	<context:property-placeholder order="0" ignore-unresolvable="true"
-		 properties-ref="security.override.properties" />
-	<util:properties id="security.override.properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
-		<prop key="fetchCertificateChain">false</prop>
-		<prop key="suppressRewriteEngine">true</prop>
-		<prop key="requiredChannel">any</prop>
-	</util:properties>
-
-	<!-- No JMX support; assume too unsafe. -->
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl b/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
deleted file mode 100644
index d706fed..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_email.vtmpl
+++ /dev/null
@@ -1,15 +0,0 @@
-Your workflow, $name, has #if( $prop_exitcode == 0)finished#{else}failed#{end}.
-
-It started execution at ${startTime}.
-It finished execution at ${finishTime}.
-
-For further information, go to $uriBuilder.build() before the run is
-automatically deleted (currently scheduled to happen at ${expiryTime}).
-
-#if( $prop_exitcode == 0)
-Exit code: $prop_exitcode
-Standard error:
-$prop_stderr
-#end
-
-(This message was automatically generated by Taverna Server ${serverVersion}.)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl b/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
deleted file mode 100644
index b595931..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_sms.vtmpl
+++ /dev/null
@@ -1 +0,0 @@
-Taverna Server ${serverVersion}: Workflow "$name" from ${startTime} has #if( $prop_exitcode == 0)finished#{else}failed#{end}.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl b/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
deleted file mode 100644
index cd920a7..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/lib/org.taverna.server.master.worker.VelocityCompletionNotifier_twitter.vtmpl
+++ /dev/null
@@ -1 +0,0 @@
-Your workflow, $name, has #if( $prop_exitcode == 0)finished#{else}failed#{end}. $uriBuilder.build() #TavernaServer ${serverVersion}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/partsecure.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/partsecure.xml b/server-webapp/src/main/webapp/WEB-INF/partsecure.xml
deleted file mode 100644
index 2e27b81..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/partsecure.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2011-2012 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:util="http://www.springframework.org/schema/util"
-	xmlns:security="http://www.springframework.org/schema/security"
-	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
-		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
-
-	<description>
-		The Taverna Server bean, plus supporting configuration.
-		THIS IS THE CONFIGURATION FOR SEMI-SECURE OPERATION ON WINDOWS.
-	</description>
-
-	<import resource="webappBeans.xml" />
-
-	<!-- This is all the same as the secure config *EXCEPT* for this override. -->
-	<context:property-placeholder order="0" ignore-unresolvable="true"
-		 properties-ref="security.override.properties" />
-	<util:properties id="security.override.properties">
-		<prop key="backEndFactory">org.taverna.server.master.localworker.ForkRunFactory</prop>
-		<prop key="fetchCertificateChain">true</prop>
-		<prop key="suppressRewriteEngine">false</prop>
-		<prop key="requiredChannel">https</prop>
-	</util:properties>
-
-	<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
-		<property name="locateExistingServerIfPossible" value="true" />
-	</bean>
-	<context:mbean-export server="MBeanServer"
-		default-domain="${my.domain}" registration="ignoreExisting" />
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/providers.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/providers.xml b/server-webapp/src/main/webapp/WEB-INF/providers.xml
deleted file mode 100644
index 43531ab..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/providers.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:util="http://www.springframework.org/schema/util"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
-
-	<import resource="beans.xml" />
-
-	<bean id="ExceptionProvider.BadInputPortName" class="org.taverna.server.master.rest.handler.BadInputPortNameHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.BadPropertyValue" class="org.taverna.server.master.rest.handler.BadPropertyValueHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.BadStateChange" class="org.taverna.server.master.rest.handler.BadStateChangeHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.FilesystemAccess" class="org.taverna.server.master.rest.handler.FilesystemAccessHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.GeneralFailure" class="org.taverna.server.master.rest.handler.GeneralFailureHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.IllegalArgument" class="org.taverna.server.master.rest.handler.IllegalArgumentHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.ImplementationProblem"
-		class="org.taverna.server.master.rest.handler.ImplementationProblemHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.InvalidCredential" class="org.taverna.server.master.rest.handler.InvalidCredentialHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoCreate" class="org.taverna.server.master.rest.handler.NoCreateHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.Overloaded" class="org.taverna.server.master.rest.handler.OverloadedHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoCredential" class="org.taverna.server.master.rest.handler.NoCredentialHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoDestroy" class="org.taverna.server.master.rest.handler.NoDestroyHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoDirectoryEntry" class="org.taverna.server.master.rest.handler.NoDirectoryEntryHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoListener" class="org.taverna.server.master.rest.handler.NoListenerHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NoUpdate" class="org.taverna.server.master.rest.handler.NoUpdateHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.NotOwner" class="org.taverna.server.master.rest.handler.NotOwnerHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.UnknownRun" class="org.taverna.server.master.rest.handler.UnknownRunHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.JAXBException" class="org.taverna.server.master.rest.handler.JAXBExceptionHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-	<bean id="ExceptionProvider.AccessDenied" class="org.taverna.server.master.rest.handler.AccessDeniedHandler">
-		<property name="managementModel" ref="webapp.state" />
-	</bean>
-    <bean id="ExceptionProvider.NegotiationFailed" class="org.taverna.server.master.rest.handler.NegotiationFailedHandler">
-    </bean>
-	<bean id="MessagingProvider.File" class="org.taverna.server.master.rest.handler.FileMessageHandler">
-		<property name="maxChunkSize" value="${default.messageSize}" />
-	</bean>
-	<bean id="MessagingProvider.FileConcatenation" class="org.taverna.server.master.rest.handler.FileConcatenationHandler">
-		<property name="maxChunkSize" value="${default.messageSize}" />
-	</bean>
-	<bean id="MessagingProvider.FileSegment" class="org.taverna.server.master.rest.handler.FileSegmentHandler">
-		<property name="maxChunkSize" value="${default.messageSize}" />
-	</bean>
-	<bean id="MessagingProvider.InputStream"
-		class="org.taverna.server.master.rest.handler.InputStreamMessageHandler">
-	</bean>
-	<bean id="MessagingProvider.T2flow" class="org.taverna.server.master.rest.handler.T2FlowDocumentHandler">
-	</bean>
-	<bean id="MessagingProvider.Permission" class="org.taverna.server.master.rest.handler.PermissionHandler">
-	</bean>
-
-	<bean id="Provider.RuntimeExceptionRemapping" class="org.taverna.server.master.utils.RuntimeExceptionWrapper" />
-	<bean id="MessagingProvider.ZipStream" class="org.taverna.server.master.rest.handler.ZipStreamHandler" />
-	<bean id="MessagingProvider.URIList" class="org.taverna.server.master.rest.handler.URIListHandler" />
-	<bean id="Interceptor.FlushThreadLocalCache"
-		class="org.taverna.server.master.utils.FlushThreadLocalCacheInterceptor"
-		lazy-init="false">
-	</bean>
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/secure.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/secure.xml b/server-webapp/src/main/webapp/WEB-INF/secure.xml
deleted file mode 100644
index cf08083..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/secure.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:util="http://www.springframework.org/schema/util"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:security="http://www.springframework.org/schema/security"
-	xsi:schemaLocation="
-	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
-	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
-	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
-	http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
-
-	<description>
-		The Taverna Server bean, plus supporting configuration.
-		THIS IS THE CONFIGURATION FOR SECURE OPERATION.
-	</description>
-
-	<import resource="webappBeans.xml" />
-
-	<context:property-placeholder order="0" ignore-unresolvable="true"
-		 properties-ref="security.override.properties" />
-	<util:properties id="security.override.properties">
-		<prop key="fetchCertificateChain">true</prop>
-		<prop key="suppressRewriteEngine">false</prop>
-		<prop key="requiredChannel">https</prop>
-	</util:properties>
-
-	<bean id="MBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
-		<property name="locateExistingServerIfPossible" value="true" />
-	</bean>
-	<context:mbean-export server="MBeanServer"
-		default-domain="${my.domain}" registration="ignoreExisting" />
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/security/users.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/security/users.properties b/server-webapp/src/main/webapp/WEB-INF/security/users.properties
deleted file mode 100644
index 03f8436..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/security/users.properties
+++ /dev/null
@@ -1,48 +0,0 @@
-# This is a Java properties file that defines the default users supported by
-# Taverna Server. The keys are the user names, and the values are comma-
-# -separated lists of values: the first is the password (which must not have
-# any spaces or commas in) and the last is "enabled" or "disabled" to indicate
-# whether this user is actually allowed to log in or not. The values between
-# are the authorities associated with the user: these are either roles (which
-# describe a particular set of permissions for the user) or user mappings.
-#
-# The supported set of authorities are:
-#
-#   ROLE_tavernauser      - may use the standard Taverna Server interfaces
-#
-#   ROLE_tavernasuperuser - may use the admin interfaces and see *all*
-#                           workflow runs irrespective of permissions
-#
-#   LOCALUSER_*           - map the server user to the given local system
-#                           account (i.e., the account name is in place of the
-#                           "*" in the authority); don't grant two of these
-#                           authorities at once, or confusion will reign
-#
-# Note that it is usually better to define accounts via the administrative
-# interface or through the JMX interface because those can then be modified
-# without restarting the server; anything in this file is fixed until the
-# next server restart. This file exists mainly to allow permissions for the
-# admin interface to be boot-strapped.
-
-# ---------------------------------------------------------------------
-
-# A normal user. Must have given role (ROLE_tavernauser) to use Taverna Server.
-# The user has password "taverna" and is enabled. The default mapping to user
-# accounts - using the user name - will be used.
-
-taverna: taverna,ROLE_tavernauser,enabled
-
-# Another normal user (username: "taverna_alt"). Will be mapped to the system
-# account called "taverna", but the user is currently disabled.
-
-taverna_alt: qwerty,ROLE_tavernauser,LOCALUSER_taverna,disabled
-
-# The default admin user, who has password "admin". You should change this!
-# Admin users also have ROLE_tavernasuperuser, which grants access to the
-# server's /admin pages and allows all workflow runs to be seen (if the
-# ROLE_tavernauser is also assigned, as below; one does not imply the other).
-# If you don't have any enabled admin users, you'll need to use JMX to do
-# management operations (JMX is only accessible from the local host and by
-# the overall container user or the system administrator).
-
-admin: admin,ROLE_tavernauser,ROLE_tavernasuperuser,LOCALUSER_taverna,enabled

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties b/server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
deleted file mode 100644
index 9616a45..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/tavernaserver.properties
+++ /dev/null
@@ -1,77 +0,0 @@
-# Override the hostname, port and webapp; leave at 'NONE' if no override
-# desired. If set, set it to something like:
-#      foo.example.com:8000/tav-serv
-default.webapp:			NONE
-# User name to use if nothing else specified
-default.localusername:	taverna
-# How to pick a user name out of a global identity
-localusernameregexp:	^TAVERNAUSER=(.*)$
-# General defaults
-default.logworkflows:	false
-default.logexceptions:	false
-default.permitsubmit:	true
-default.lifetime:		1440
-default.runlimit:		100
-default.operatinglimit:	10
-default.messageSize:	65536
-#taverna.preferredUserUri:	https://some.host:8443/tavernaserver/rest/
-http.realmName:         tavernaserver
-
-rmi.localhostOnly:		true
-helio.cis.enableTokenPassing:	false
-log.security.details:	false
-
-#executeWorkflowScript:	/usr/taverna/executeworkflow.sh
-#secureForkPasswordFile:	/usr/local/tomcat6.0/conf/sudopass.txt
-
-# Usage Record handling
-usage.logFile:		none
-usage.disableDB:	no
-
-# Delays used in the task executor 
-purge.interval:		30000
-finish.interval:	10000
-
-# Static configuration of messaging
-
-### Email
-email.from:		taverna.server@localhost
-email.type:		text/plain
-#email.host:	localhost
-
-### Jabber
-#xmpp.server:	xmpp://some.host:5222
-xmpp.resource:	TavernaServer
-#xmpp.user:		taverna
-#xmpp.password:	*******
-
-### Atom/RSS; lifespan in days, cleaninterval in milliseconds
-atom.language:	en
-atom.lifespan:	7
-atom.cleaninterval:	3600000
-
-### SMS
-#sms.service:	https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx
-sms.userfield:	username
-sms.passfield:	password
-sms.destfield:	to
-sms.msgfield:	text
-#sms.user:		taverna
-#sms.pass:		*******
-
-### Twitter
-#twitter.oauth.accessToken:			...
-#twitter.oauth.accessTokenSecret:	...
-
-### General; cooldown in seconds
-message.cooldown:				300
-message.termination.subject:	Taverna workflow run finished
-message.termination.body:		Your job with ID={0} has finished with exit code {1,number,integer}.
-
-# Thread pool sizing
-pool.size:	2
-
-taverna.interaction.host:			none
-taverna.interaction.port:			none
-taverna.interaction.webdav_path:	none
-taverna.interaction.feed_path:		none

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/web-nosec.xml b/server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
deleted file mode 100644
index d6c6ee7..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/web-nosec.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!DOCTYPE web-app
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-
-<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<web-app id="TAVSERV-2.5.4">
-	<display-name>Taverna 2.5.4 Server</display-name>
-	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
-	<context-param>
-		<param-name>contextConfigLocation</param-name>
-		<param-value>WEB-INF/insecure.xml</param-value>
-		<description>Where Spring is to load its bean definitions from. DO NOT
-			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
-	</context-param>
-	<context-param>
-		<param-name>log4jExposeWebAppRoot</param-name>
-		<param-value>false</param-value>
-		<description>
-			THIS IS STUPID! We have to do this so that Tomcat webapps do not
-			leak their configurations into each other via the log4j support
-			trying to be "smart".
-			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
-			If you change this, good luck hunting down the weird crashes.
-		</description>
-	</context-param>
-
-	<filter>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<url-pattern>/*</url-pattern>
-	</filter-mapping>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.request.RequestContextListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.util.Log4jConfigListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.ContextLoaderListener
-		</listener-class>
-	</listener>
-
-	<servlet>
-		<servlet-name>CXFServlet</servlet-name>
-		<display-name>CXF Servlet</display-name>
-		<servlet-class>
-			org.apache.cxf.transport.servlet.CXFServlet
-		</servlet-class>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>CXFServlet</servlet-name>
-		<url-pattern>/*</url-pattern>
-	</servlet-mapping>
-
-	<resource-ref>
-		<description>
-			Resource reference to a factory for javax.mail.Session
-			instances that may be used for sending electronic mail
-			messages, preconfigured to connect to the appropriate
-			SMTP server.
-		</description>
-		<res-ref-name>mail/Session</res-ref-name>
-		<res-type>javax.mail.Session</res-type>
-		<res-auth>Container</res-auth>
-		<res-sharing-scope>Shareable</res-sharing-scope>
-	</resource-ref>
-</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/web-partsec.xml b/server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
deleted file mode 100644
index a2b545e..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/web-partsec.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!DOCTYPE web-app
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-
-<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<web-app id="TAVSERV-2.5.4">
-	<display-name>Taverna 2.5.4 Server</display-name>
-	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
-	<context-param>
-		<param-name>contextConfigLocation</param-name>
-		<param-value>WEB-INF/partsecure.xml</param-value>
-		<description>Where Spring is to load its bean definitions from. DO NOT
-			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
-	</context-param>
-	<context-param>
-		<param-name>log4jExposeWebAppRoot</param-name>
-		<param-value>false</param-value>
-		<description>
-			THIS IS STUPID! We have to do this so that Tomcat webapps do not
-			leak their configurations into each other via the log4j support
-			trying to be "smart".
-			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
-			If you change this, good luck hunting down the weird crashes.
-		</description>
-	</context-param>
-
-	<filter>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<url-pattern>/*</url-pattern>
-	</filter-mapping>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.request.RequestContextListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.util.Log4jConfigListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.ContextLoaderListener
-		</listener-class>
-	</listener>
-
-	<servlet>
-		<servlet-name>CXFServlet</servlet-name>
-		<display-name>CXF Servlet</display-name>
-		<servlet-class>
-			org.apache.cxf.transport.servlet.CXFServlet
-		</servlet-class>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>CXFServlet</servlet-name>
-		<url-pattern>/*</url-pattern>
-	</servlet-mapping>
-
-	<resource-ref>
-		<description>
-			Resource reference to a factory for javax.mail.Session
-			instances that may be used for sending electronic mail
-			messages, preconfigured to connect to the appropriate
-			SMTP server.
-		</description>
-		<res-ref-name>mail/Session</res-ref-name>
-		<res-type>javax.mail.Session</res-type>
-		<res-auth>Container</res-auth>
-		<res-sharing-scope>Shareable</res-sharing-scope>
-	</resource-ref>
-</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/web-sec.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/web-sec.xml b/server-webapp/src/main/webapp/WEB-INF/web-sec.xml
deleted file mode 100644
index 9a5395a..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/web-sec.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<!DOCTYPE web-app
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-
-<!-- Copyright (C) 2010-2011 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<web-app id="TAVSERV-2.5.4">
-	<display-name>Taverna 2.5.4 Server</display-name>
-	<description>This is the front-end engine for Taverna 2.5.4 Server.</description>
-	<context-param>
-		<param-name>contextConfigLocation</param-name>
-		<param-value>WEB-INF/secure.xml</param-value>
-		<description>Where Spring is to load its bean definitions from. DO NOT
-			CHANGE WITHOUT CONSULTING DOCUMENTATION.</description>
-	</context-param>
-	<context-param>
-		<param-name>log4jExposeWebAppRoot</param-name>
-		<param-value>false</param-value>
-		<description>
-			THIS IS STUPID! We have to do this so that Tomcat webapps do not
-			leak their configurations into each other via the log4j support
-			trying to be "smart".
-			http://javacolors.blogspot.co.uk/2010/08/tomcat-and-webxmls-webapprootkey.html
-			If you change this, good luck hunting down the weird crashes.
-		</description>
-	</context-param>
-
-	<filter>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
-	</filter>
-	<filter-mapping>
-		<filter-name>springSecurityFilterChain</filter-name>
-		<url-pattern>/*</url-pattern>
-	</filter-mapping>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.request.RequestContextListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.util.Log4jConfigListener
-		</listener-class>
-	</listener>
-	<listener>
-		<listener-class>
-			org.springframework.web.context.ContextLoaderListener
-		</listener-class>
-	</listener>
-
-	<servlet>
-		<servlet-name>CXFServlet</servlet-name>
-		<display-name>CXF Servlet</display-name>
-		<servlet-class>
-			org.apache.cxf.transport.servlet.CXFServlet
-		</servlet-class>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-
-	<servlet-mapping>
-		<servlet-name>CXFServlet</servlet-name>
-		<url-pattern>/*</url-pattern>
-	</servlet-mapping>
-
-	<resource-ref>
-		<description>
-			Resource reference to a factory for javax.mail.Session
-			instances that may be used for sending electronic mail
-			messages, preconfigured to connect to the appropriate
-			SMTP server.
-		</description>
-		<res-ref-name>mail/Session</res-ref-name>
-		<res-type>javax.mail.Session</res-type>
-		<res-auth>Container</res-auth>
-		<res-sharing-scope>Shareable</res-sharing-scope>
-	</resource-ref>
-</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/webapp/WEB-INF/webappBeans.xml b/server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
deleted file mode 100644
index 22e74b3..0000000
--- a/server-webapp/src/main/webapp/WEB-INF/webappBeans.xml
+++ /dev/null
@@ -1,213 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2010-2012 The University of Manchester See the file "LICENSE" 
-	for license terms. -->
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:aop="http://www.springframework.org/schema/aop"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:jaxrs="http://cxf.apache.org/jaxrs"
-	xmlns:jaxws="http://cxf.apache.org/jaxws"
-	xmlns:cxf="http://cxf.apache.org/core"
-	xmlns:security="http://www.springframework.org/schema/security"
-	xmlns:util="http://www.springframework.org/schema/util"
-	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
-		http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
-		http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
-		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
-		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
-		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
-		http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
-		http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
-		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
-
-	<description>
-		The Taverna Server bean, plus supporting configuration.
-	</description>
-
-	<import resource="classpath:META-INF/cxf/cxf.xml" />
-	<import resource="providers.xml" />
-
-	<context:annotation-config />
-	<context:component-scan base-package="org.taverna.server" />
-	<bean id="servletContextPropertyConfigurer"
-		class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
-		<property name="ignoreUnresolvablePlaceholders" value="true" />
-		<property name="localOverride" value="true" />
-		<property name="order" value="0" />
-		<property name="location" value="/WEB-INF/tavernaserver.properties" />
-	</bean>
-
-	<jaxws:server id="master_SOAP"
-		serviceClass="org.taverna.server.master.TavernaServer" address="/soap">
-		<jaxws:serviceBean>
-			<ref bean="webapp" />
-		</jaxws:serviceBean>
-		<jaxws:properties>
-			<entry key="mtom-enabled" value="true" />
-		</jaxws:properties>
-		<!-- <jaxws:dataBinding><ref bean="addStylesheet"/></jaxws:dataBinding> -->
-	</jaxws:server>
-
-	<jaxrs:server id="root_REST" address="/">
-		<jaxrs:serviceBeans>
-			<ref bean="root_facade" />
-		</jaxrs:serviceBeans>
-		<jaxrs:properties>
-			<entry key="org.apache.cxf.endpoint.private" value="true" />
-		</jaxrs:properties>
-	</jaxrs:server>
-
-	<jaxrs:server id="master_REST" address="/rest"
-		staticSubresourceResolution="true">
-		<jaxrs:serviceBeans>
-			<ref bean="webapp" />
-		</jaxrs:serviceBeans>
-		<jaxrs:features>
-			<!-- <cxf:logging /> --><!-- NOISY! -->
-		</jaxrs:features>
-		<jaxrs:providers>
-			<ref bean="ExceptionProvider.AccessDenied" />
-			<ref bean="ExceptionProvider.BadInputPortName" />
-			<ref bean="ExceptionProvider.BadPropertyValue" />
-			<ref bean="ExceptionProvider.BadStateChange" />
-			<ref bean="ExceptionProvider.FilesystemAccess" />
-			<ref bean="ExceptionProvider.GeneralFailure" />
-			<ref bean="ExceptionProvider.IllegalArgument" />
-			<ref bean="ExceptionProvider.ImplementationProblem" />
-			<ref bean="ExceptionProvider.InvalidCredential" />
-			<ref bean="ExceptionProvider.JAXBException" />
-			<ref bean="ExceptionProvider.NegotiationFailed" />
-			<ref bean="ExceptionProvider.NoCreate" />
-			<ref bean="ExceptionProvider.NoCredential" />
-			<ref bean="ExceptionProvider.NoDestroy" />
-			<ref bean="ExceptionProvider.NoDirectoryEntry" />
-			<ref bean="ExceptionProvider.NoListener" />
-			<ref bean="ExceptionProvider.NoUpdate" />
-			<ref bean="ExceptionProvider.NotOwner" />
-			<ref bean="ExceptionProvider.Overloaded" />
-			<ref bean="ExceptionProvider.UnknownRun" />
-			<ref bean="MessagingProvider.File" />
-			<ref bean="MessagingProvider.FileConcatenation" />
-			<ref bean="MessagingProvider.FileSegment" />
-			<ref bean="MessagingProvider.InputStream" />
-			<ref bean="MessagingProvider.T2flow" />
-			<ref bean="MessagingProvider.Permission" />
-			<ref bean="MessagingProvider.URIList" />
-			<ref bean="MessagingProvider.ZipStream" />
-			<ref bean="jsonProvider" />
-			<ref bean="atomEntryHandler" />
-			<ref bean="atomFeedHandler" />
-			<bean class="org.apache.cxf.jaxrs.model.wadl.WadlGenerator">
-				<property name="addResourceAndMethodIds" value="true"/>
-			</bean>
-		</jaxrs:providers>
-		<jaxrs:outInterceptors>
-			<ref bean="Interceptor.FlushThreadLocalCache" />
-		</jaxrs:outInterceptors>
- 	</jaxrs:server>
-
-	<jaxrs:server id="AtomFeed" address="/feed">
-		<jaxrs:serviceBeans>
-			<ref bean="feed" />
-		</jaxrs:serviceBeans>
-		<jaxrs:properties>
-			<entry key="org.apache.cxf.endpoint.private" value="true" />
-		</jaxrs:properties>
-		<jaxrs:providers>
-			<ref bean="atomEntryHandler" />
-			<ref bean="atomFeedHandler" />
-		</jaxrs:providers>
-	</jaxrs:server>
-
-	<jaxrs:server id="AdministrationInterface" address="/admin"
-		staticSubresourceResolution="true">
-		<jaxrs:serviceBeans>
-			<ref bean="admin" />
-		</jaxrs:serviceBeans>
-		<jaxrs:providers>
-			<ref bean="jsonProvider" />
-		</jaxrs:providers>
-	</jaxrs:server>
-
-	<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
-		<property name="ignoreNamespaces" value="true" />
-		<property name="namespaceMap" ref="jsonNamespaceMap" />
-	</bean>
-	<util:map id="jsonNamespaceMap" key-type="java.lang.String"
-		value-type="java.lang.String">
-		<entry key="http://www.w3.org/1999/xlink" value="" />
-		<entry key="http://www.w3.org/2000/09/xmldsig#" value="" />
-		<entry key="http://schema.ogf.org/urf/2003/09/urf" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/xml/server/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/xml/server/rest/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/xml/server/soap/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/xml/server/feed/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/xml/server/admin/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/port/" value="" />
-		<entry key="http://ns.taverna.org.uk/2010/run/" value="" />
-	</util:map>
-
-	<bean id="root_facade" class="org.taverna.server.master.facade.Facade">
-		<property name="file" value="/welcome.html" />
-		<property name="contextualizer" ref="contextualizer" />
-	</bean>
-
-	<bean class="org.taverna.server.master.common.Uri.Rewriter"
-		autowire="byType" id="URI-Rewriter-Thunk">
-		<property name="suppressSecurity" value="${suppressRewriteEngine}" />
-		<property name="rewriteTarget" value="${default.webapp}" />
-	</bean>
-	<security:authentication-manager>
-		<security:authentication-provider ref="workflowInternalAuthProvder" />
-		<security:authentication-provider ref="authProvider" />
-	</security:authentication-manager>
-
-	<bean id="WSDLHeadOptionsInterceptor"
-		class="org.taverna.server.master.utils.WSDLHeadOptionsInterceptor" />
-	<cxf:bus>
-		<cxf:inInterceptors>
-			<ref bean="WSDLHeadOptionsInterceptor" />
-		</cxf:inInterceptors>
-	</cxf:bus>
-
-	<aop:aspectj-autoproxy proxy-target-class="true" />
-	<security:global-method-security
-		jsr250-annotations="enabled" />
-
-	<security:http realm="${http.realmName}" create-session="never"
-		use-expressions="true">
-		<security:http-basic />
-		<security:intercept-url pattern="/"
-			requires-channel="any" access="permitAll" />
-		<security:intercept-url pattern="/rest"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/rest/"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/rest/policy"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/rest/policy/"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/services/**"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/soap/**" method="GET"
-			requires-channel="${requiredChannel}" access="permitAll" />
-		<security:intercept-url pattern="/soap/**" method="POST"
-			requires-channel="${requiredChannel}"
-			access="hasRole('ROLE_tavernauser')" />
-		<security:intercept-url pattern="/admin"
-			requires-channel="${requiredChannel}"
-			access="hasRole('ROLE_tavernasuperuser')" />
-		<security:intercept-url pattern="/admin/**"
-			requires-channel="${requiredChannel}"
-			access="hasRole('ROLE_tavernasuperuser')" />
-		<security:intercept-url pattern="/rest/**"
-			requires-channel="${requiredChannel}"
-			access="hasAnyRole('ROLE_tavernauser','ROLE_tavernaworkflow')" />
-		<security:intercept-url pattern="/feed"
-			requires-channel="${requiredChannel}"
-			access="hasRole('ROLE_tavernauser')" />
-		<security:intercept-url pattern="/feed/**"
-			requires-channel="${requiredChannel}"
-			access="hasRole('ROLE_tavernauser')" />
-	</security:http>
-</beans>


[04/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js b/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
new file mode 100644
index 0000000..7835454
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
@@ -0,0 +1,125 @@
+/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.core.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number
 "?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelectio
 n:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.cre
 atePseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScr
 oll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.widget.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e
 ].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(
 this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||
 c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.mouse.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.del
 ay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this.
 _mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.position.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),
 n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left
 )},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.
 curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuer
 y);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.draggable.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return thi
 s.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),rel
 ative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!
 this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle
 ||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){thi
 s.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop")
 ,10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|wind
 ow|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="abs
 olute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h
 =[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version
 <526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.23"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(
 this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g
 =b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=
 this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")
 ),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensit
 ivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.pu
 sh({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left
 :0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{st
 art:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.droppable.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=
 a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;r
 eturn this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.23"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.lef
 t,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.lengt
 h;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.opt
 ions.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.resizable.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data(
 "resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne
 ,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseov
 er(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCaptu
 re:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalM
 ousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigg
 er("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.mi
 nHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=thi
 s.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borde
 rLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSiz
 e.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:thi
 s.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.23"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?[
 "width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),1
 0),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i
 ,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d
 .sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.
 originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.
 width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.selectable.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mou
 seStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unsele
 cting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selec
 ting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.23"})})
 (jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.sortable.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return thi
 s},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset
 (),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIn
 dex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scro
 llParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollL
 eft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseS
 top:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return 
 this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top
 ,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.c
 lick.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options
 .items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=
 a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.con
 tainers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft
 ")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui
 .contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]
 ),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.cont
 ains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}}
 ,_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("bo
 rderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d
 )}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click
 .top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling)
 ,this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._u
 iHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._t
 rigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.accordion.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this)
 .removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("
 tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex
 "),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._c

<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/t2cogs.png
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/t2cogs.png b/taverna-server-webapp/src/main/resources/static/t2cogs.png
new file mode 100644
index 0000000..a93b3bd
Binary files /dev/null and b/taverna-server-webapp/src/main/resources/static/t2cogs.png differ


[49/49] incubator-taverna-server git commit: simplified in some poms

Posted by st...@apache.org.
simplified <name> in some poms


Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/commit/8d121b2b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/tree/8d121b2b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/diff/8d121b2b

Branch: refs/heads/master
Commit: 8d121b2b07cb4ab6580ba58fd30ec64fb34566cb
Parents: 2c71f9a
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Mon Feb 23 15:36:47 2015 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Mon Feb 23 15:36:47 2015 +0000

----------------------------------------------------------------------
 taverna-server-port-description/pom.xml | 2 +-
 taverna-server-runinterface/pom.xml     | 5 +++--
 taverna-server-worker/pom.xml           | 6 ++++--
 3 files changed, 8 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/8d121b2b/taverna-server-port-description/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-port-description/pom.xml b/taverna-server-port-description/pom.xml
index 99582ed..c49310e 100644
--- a/taverna-server-port-description/pom.xml
+++ b/taverna-server-port-description/pom.xml
@@ -23,7 +23,7 @@ limitations under the License.
 		<version>3.1.0-incubating-SNAPSHOT</version>
 	</parent>
 	<artifactId>taverna-server-port-description</artifactId>
-	<name>Apache Taverna Server Workflow Port Descriptor Types</name>
+	<name>Apache Taverna Server Workflow Port Descriptors</name>
 	<description>The structural types used to describe ports on workflows, as exported by Taverna Server.</description>
 
 	<properties>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/8d121b2b/taverna-server-runinterface/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-runinterface/pom.xml b/taverna-server-runinterface/pom.xml
index efd3763..3509180 100644
--- a/taverna-server-runinterface/pom.xml
+++ b/taverna-server-runinterface/pom.xml
@@ -24,7 +24,8 @@ limitations under the License.
 	</parent>
 
 	<artifactId>taverna-server-runinterface</artifactId>
-	<name>Apache Taverna Server RMI Interface: Webapp &lt;-&gt; Worker</name>
-	<description>This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description>
+  <name>Apache Taverna Server Run interface (RMI)</name>
+  <description>RMI Interface: Webapp &lt;-&gt; Worker.
+    This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description>
 
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/8d121b2b/taverna-server-worker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-worker/pom.xml b/taverna-server-worker/pom.xml
index 8006c6d..f368b1b 100644
--- a/taverna-server-worker/pom.xml
+++ b/taverna-server-worker/pom.xml
@@ -23,8 +23,10 @@ limitations under the License.
 		<version>3.1.0-incubating-SNAPSHOT</version>
 	</parent>
 	<artifactId>taverna-server-worker</artifactId>
-	<name>Apache Taverna Server Workflow Executor/File System Access Process Implementation</name>
-	<description>This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
+	<name>Apache Taverna Server Worker</name>
+  <description>
+    Apache Taverna Server Workflow Executor/File System Access Process Implementation.
+    This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
 
 	<properties>
 		<workerMainClass>org.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>


[41/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java b/server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
deleted file mode 100644
index 69c3622..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/ProfileList.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE.txt" for license terms.
- */
-package org.taverna.server.master.common;
-
-import java.util.ArrayList;
-import java.util.List;
-
-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 the profiles that can apply to a workflow.
- * 
- * @author Donal K. Fellows
- */
-@XmlRootElement(name = "profiles")
-@XmlType(name = "ProfileList")
-public class ProfileList {
-	public List<ProfileList.Info> profile = new ArrayList<ProfileList.Info>();
-
-	/**
-	 * Description of a single workflow profile.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "profile")
-	@XmlType(name = "Profile")
-	public static class Info {
-		@XmlValue
-		public String name;
-		/**
-		 * Whether this is the main profile.
-		 */
-		@XmlAttribute(name = "isMain")
-		public Boolean main;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Roles.java b/server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
deleted file mode 100644
index 8079b1c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Roles.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-/**
- * The roles defined in this webapp.
- * 
- * @author Donal Fellows
- */
-public interface Roles {
-	/** The role of a normal user. */
-	static final String USER = "ROLE_tavernauser";
-	/**
-	 * The role of an administrator. Administrators <i>should</i> have the
-	 * normal user role as well.
-	 */
-	static final String ADMIN = "ROLE_tavernasuperuser";
-	/**
-	 * The role of a workflow accessing itself. Do not give users this role.
-	 */
-	static final String SELF = "ROLE_tavernaworkflow";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java b/server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
deleted file mode 100644
index 3486bf7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/RunReference.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.master.common.VersionedElement.VERSION;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-/**
- * A reference to a single workflow run, described using JAXB.
- * 
- * @author Donal Fellows
- * @see org.taverna.server.master.interfaces.TavernaRun TavernaRun
- */
-@XmlRootElement
-@XmlType(name = "TavernaRun")
-@XmlSeeAlso( { Workflow.class, DirEntryReference.class })
-public class RunReference {
-	/**
-	 * Where to get information about the run. For REST.
-	 */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	/** What version of server produced this element? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverVersion;
-	/**
-	 * The name of the run. For SOAP.
-	 */
-	@XmlValue
-	public String name;
-
-	/**
-	 * Make a blank run reference.
-	 */
-	public RunReference() {
-	}
-
-	/**
-	 * Make a reference to the given workflow run.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param ub
-	 *            A factory for URIs, or <tt>null</tt> if none is to be made.
-	 */
-	public RunReference(String name, UriBuilder ub) {
-		this.serverVersion = VERSION;
-		this.name = name;
-		if (ub != null)
-			this.link = ub.build(name);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Status.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Status.java b/server-webapp/src/main/java/org/taverna/server/master/common/Status.java
deleted file mode 100644
index 8e360dc..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Status.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import javax.xml.bind.annotation.XmlEnum;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * States of a workflow run. They are {@link #Initialized Initialized},
- * {@link #Operating Operating}, {@link #Stopped Stopped}, and {@link #Finished
- * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the
- * workflow run does not exist (and hence can't have its state queried or set)
- * in that case.
- * 
- * @author Donal Fellows
- */
-@XmlEnum
-@XmlType(name = "Status")
-public enum Status {
-	/**
-	 * The workflow run has been created, but is not yet running. The run will
-	 * need to be manually moved to {@link #Operating Operating} when ready.
-	 */
-	Initialized,
-	/**
-	 * The workflow run is going, reading input, generating output, etc. Will
-	 * eventually either move automatically to {@link #Finished Finished} or can
-	 * be moved manually to {@link #Stopped Stopped} (where supported).
-	 */
-	Operating,
-	/**
-	 * The workflow run is paused, and will need to be moved back to
-	 * {@link #Operating Operating} manually.
-	 */
-	Stopped,
-	/**
-	 * The workflow run has ceased; data files will continue to exist until the
-	 * run is destroyed (which may be manual or automatic).
-	 */
-	Finished
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Trust.java b/server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
deleted file mode 100644
index 6d77aa7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Trust.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.io.Serializable;
-import java.security.cert.Certificate;
-import java.util.Collection;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * A description of a trusted identity or identities. This description is
- * characterised by a file visible to the workflow run that contains one or more
- * certificates.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "TrustDescriptor")
-@XmlRootElement(name = "trustedIdentity")
-@SuppressWarnings("serial")
-public final class Trust implements Serializable {
-	/** The location of this descriptor in the REST world. */
-	@XmlAttribute(namespace = XLINK)
-	public String href;
-	/**
-	 * The location of this descriptor in the SOAP world. Must match corrected
-	 * with the {@link #href} field.
-	 */
-	@XmlTransient
-	public String id;
-	/**
-	 * The file containing the certificate(s). This is resolved with respect to
-	 * the workflow run working directory.
-	 */
-	@XmlElement
-	public String certificateFile;
-	/**
-	 * The type of certificate file. Defaults to <tt>X.509</tt> if unspecified.
-	 */
-	@XmlElement
-	public String fileType;
-	/**
-	 * The encoded serialized keystore containing the certificate(s).
-	 */
-	@XmlElement
-	public byte[] certificateBytes;
-	/**
-	 * The names of the server(s) identified by this trust.
-	 */
-	@XmlElement
-	public List<String> serverName;
-	/**
-	 * The collection of certificates loaded from the specified file. This is
-	 * always <tt>null</tt> before validation.
-	 */
-	public transient Collection<? extends Certificate> loadedCertificates;
-
-	@Override
-	public int hashCode() {
-		return id.hashCode();
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (o == null || !(o instanceof Trust))
-			return false;
-		return id.equals(((Trust) o).id);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Uri.java b/server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
deleted file mode 100644
index d6d057c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Uri.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriBuilderException;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.web.PortMapper;
-
-import javax.annotation.Nonnull;
-
-/**
- * A class that makes it simpler to work with an element with a {@link URI} in
- * an <tt>href</tt> attribute. Done with JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "Location")
-public class Uri {
-	static Log log = getLog("Taverna.Server.UriRewriter");
-	private static final String SECURE_SCHEME = "https";
-	/**
-	 * This type is characterised by an attribute that is the reference to some
-	 * other element.
-	 */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI ref;
-
-	/** Make a reference that points nowhere. */
-	public Uri() {
-	}
-
-	/**
-	 * Make a reference to the given location.
-	 * 
-	 * @param ref
-	 *            Where to point to.
-	 */
-	public Uri(@Nonnull URI ref) {
-		this.ref = secure(ref);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ub
-	 *            The configured factory.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriBuilder ub, String... strings) {
-		ref = secure(ub).build((Object[]) strings);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ui
-	 *            The factory factory.
-	 * @param path
-	 *            The path to configure the factory with.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriInfo ui, @Nonnull String path, String... strings) {
-		this(ui, true, path, strings);
-	}
-
-	/**
-	 * Make a reference from the factory with the given parameters.
-	 * 
-	 * @param ui
-	 *            The factory factory.
-	 * @param secure
-	 *            Whether the URI should be required to use HTTPS.
-	 * @param path
-	 *            The path to configure the factory with.
-	 * @param strings
-	 *            The parameters to the factory.
-	 */
-	public Uri(@Nonnull UriInfo ui, boolean secure, @Nonnull String path,
-			String... strings) {
-		UriBuilder ub = ui.getAbsolutePathBuilder();
-		if (secure) {
-			ub = secure(ub);
-		}
-		ref = ub.path(path).build((Object[]) strings);
-	}
-
-	public static UriBuilder secure(UriBuilder ub) {
-		return Rewriter.getInstance().getSecuredUriBuilder(ub);
-	}
-
-	public static UriBuilder secure(UriInfo ui) {
-		return secure(ui.getAbsolutePathBuilder());
-	}
-
-	public static URI secure(URI uri) {
-		URI newURI = secure(fromUri(uri)).build();
-		if (log.isDebugEnabled())
-			log.debug("rewrote " + uri + " to " + newURI);
-		return newURI;
-	}
-
-	public static URI secure(URI base, String uri) {
-		URI newURI = secure(fromUri(base.resolve(uri))).build();
-		if (log.isDebugEnabled())
-			log.debug("rewrote " + uri + " to " + newURI);
-		return newURI;
-	}
-
-	/**
-	 * A bean that allows configuration of how to rewrite generated URIs to be
-	 * secure.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class Rewriter {
-		private static Rewriter instance;
-		private PortMapper portMapper;
-		private boolean suppress;
-		private String rewriteRE = "://[^/]+/[^/]+";
-		private String rewriteTarget;
-
-		static Rewriter getInstance() {
-			if (instance == null)
-				new Rewriter();
-			return instance;
-		}
-
-		@Autowired
-		public void setPortMapper(PortMapper portMapper) {
-			this.portMapper = portMapper;
-		}
-
-		/**
-		 * Whether to suppress rewriting of URIs to be secure.
-		 * 
-		 * @param suppressSecurity
-		 *            True if no rewriting should be done.
-		 */
-		public void setSuppressSecurity(boolean suppressSecurity) {
-			suppress = suppressSecurity;
-		}
-
-		public void setRewriteRegexp(String rewriteRegexp) {
-			this.rewriteRE = rewriteRegexp;
-		}
-
-		/**
-		 * What to rewrite the host, port and web-app name to be.
-		 * 
-		 * @param rewriteTarget
-		 *            What to rewrite to, or "<tt>NONE</tt>" for no rewrite.
-		 */
-		public void setRewriteTarget(String rewriteTarget) {
-			if (rewriteTarget.isEmpty())
-				this.rewriteTarget = null;
-			else if (rewriteTarget.equals("NONE"))
-				this.rewriteTarget = null;
-			else if (rewriteTarget.startsWith("${"))
-				this.rewriteTarget = null;
-			else
-				this.rewriteTarget = "://" + rewriteTarget;
-		}
-
-		private Integer lookupHttpsPort(URI uri) {
-			if (portMapper != null)
-				return portMapper.lookupHttpsPort(uri.getPort());
-			return null;
-		}
-
-		public Rewriter() {
-			instance = this;
-		}
-
-		@PreDestroy
-		public void done() {
-			instance = null;
-			Uri.log = null;
-		}
-
-		@Nonnull
-		URI rewrite(@Nonnull String url) {
-			if (rewriteTarget != null)
-				url = url.replaceFirst(rewriteRE, rewriteTarget);
-			return URI.create(url);
-		}
-
-		@Nonnull
-		public UriBuilder getSecuredUriBuilder(@Nonnull UriBuilder uribuilder) {
-			if (suppress)
-				return uribuilder.clone();
-			UriBuilder ub = new RewritingUriBuilder(uribuilder);
-			Integer secPort = null;
-			try {
-				secPort = lookupHttpsPort(ub.build());
-			} catch (Exception e) {
-				/*
-				 * Do not log this; we know why it happens and don't actually
-				 * care to do anything about it. All it does is fill up the log
-				 * with pointless scariness!
-				 */
-
-				// log.debug("failed to extract current URI port", e);
-			}
-			if (secPort == null || secPort.intValue() == -1)
-				return ub.scheme(SECURE_SCHEME);
-			return ub.scheme(SECURE_SCHEME).port(secPort);
-		}
-
-		/**
-		 * {@link UriBuilder} that applies a rewrite rule to the URIs produced
-		 * by the wrapped builder.
-		 * 
-		 * @author Donal Fellows
-		 */
-		class RewritingUriBuilder extends UriBuilder {
-			private UriBuilder wrapped;
-
-			RewritingUriBuilder(UriBuilder builder) {
-				wrapped = builder.clone();
-			}
-
-			private URI rewrite(URI uri) {
-				return Rewriter.this.rewrite(uri.toString());
-			}
-
-			@Override
-			public UriBuilder clone() {
-				return new RewritingUriBuilder(wrapped);
-			}
-
-			@Override
-			public URI buildFromMap(Map<String, ?> values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromMap(values));
-			}
-
-			@Override
-			public URI buildFromEncodedMap(Map<String, ? extends Object> values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromEncodedMap(values));
-			}
-
-			@Override
-			public URI build(Object... values) throws IllegalArgumentException,
-					UriBuilderException {
-				return rewrite(wrapped.build(values));
-			}
-
-			@Override
-			public URI build(Object[] values, boolean encodeSlashInPath)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.build(values, encodeSlashInPath));
-			}
-
-			@Override
-			public URI buildFromEncoded(Object... values)
-					throws IllegalArgumentException, UriBuilderException {
-				return rewrite(wrapped.buildFromEncoded(values));
-			}
-
-			@Override
-			public URI buildFromMap(Map<String, ?> values,
-					boolean encodeSlashInPath) throws IllegalArgumentException,
-					UriBuilderException {
-				return rewrite(wrapped.buildFromEncoded(values,
-						encodeSlashInPath));
-			}
-
-			@Override
-			public UriBuilder uri(URI uri) throws IllegalArgumentException {
-				wrapped.uri(uri);
-				return this;
-			}
-
-			@Override
-			public UriBuilder uri(String uriTemplate)
-					throws IllegalArgumentException {
-				wrapped.uri(uriTemplate);
-				return this;
-			}
-
-			@Override
-			public String toTemplate() {
-				return wrapped.toTemplate();
-			}
-
-			@Override
-			public UriBuilder scheme(String scheme)
-					throws IllegalArgumentException {
-				wrapped.scheme(scheme);
-				return this;
-			}
-
-			@Override
-			public UriBuilder schemeSpecificPart(String ssp)
-					throws IllegalArgumentException {
-				wrapped.schemeSpecificPart(ssp);
-				return this;
-			}
-
-			@Override
-			public UriBuilder userInfo(String ui) {
-				wrapped.userInfo(ui);
-				return this;
-			}
-
-			@Override
-			public UriBuilder host(String host) throws IllegalArgumentException {
-				wrapped.host(host);
-				return this;
-			}
-
-			@Override
-			public UriBuilder port(int port) throws IllegalArgumentException {
-				wrapped.port(port);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replacePath(String path) {
-				wrapped.replacePath(path);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(String path) throws IllegalArgumentException {
-				wrapped.path(path);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(
-					@java.lang.SuppressWarnings("rawtypes") Class resource)
-					throws IllegalArgumentException {
-				wrapped.path(resource);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(
-					@java.lang.SuppressWarnings("rawtypes") Class resource,
-					String method) throws IllegalArgumentException {
-				wrapped.path(resource, method);
-				return this;
-			}
-
-			@Override
-			public UriBuilder path(Method method)
-					throws IllegalArgumentException {
-				wrapped.path(method);
-				return this;
-			}
-
-			@Override
-			public UriBuilder segment(String... segments)
-					throws IllegalArgumentException {
-				wrapped.segment(segments);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceMatrix(String matrix)
-					throws IllegalArgumentException {
-				wrapped.replaceMatrix(matrix);
-				return this;
-			}
-
-			@Override
-			public UriBuilder matrixParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.matrixParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceMatrixParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.replaceMatrixParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceQuery(String query)
-					throws IllegalArgumentException {
-				wrapped.replaceQuery(query);
-				return this;
-			}
-
-			@Override
-			public UriBuilder queryParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.queryParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder replaceQueryParam(String name, Object... values)
-					throws IllegalArgumentException {
-				wrapped.replaceQueryParam(name, values);
-				return this;
-			}
-
-			@Override
-			public UriBuilder fragment(String fragment) {
-				wrapped.fragment(fragment);
-				return this;
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java b/server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
deleted file mode 100644
index 6eddf2d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/VersionedElement.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.commons.logging.Log;
-
-/**
- * The type of an element that declares the version of the server that produced
- * it.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "VersionedElement", namespace = SERVER)
-public abstract class VersionedElement {
-	/** What version of server produced this element? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverVersion;
-	/** What revision of server produced this element? Derived from SCM commit. */
-	@XmlAttribute(namespace = SERVER)
-	public String serverRevision;
-	/** When was the server built? */
-	@XmlAttribute(namespace = SERVER)
-	public String serverBuildTimestamp;
-	public static final String VERSION, REVISION, TIMESTAMP;
-	static {
-		Log log = getLog("Taverna.Server.Webapp");
-		Properties p = new Properties();
-		try {
-			try (InputStream is = VersionedElement.class
-					.getResourceAsStream("/version.properties")) {
-				p.load(is);
-			}
-		} catch (IOException e) {
-			log.warn("failed to read /version.properties", e);
-		}
-		VERSION = p.getProperty("tavernaserver.version", "unknownVersion");
-		REVISION = String.format("%s (tag: %s)",
-				p.getProperty("tavernaserver.branch", "unknownRevision"),
-				p.getProperty("tavernaserver.revision.describe", "unknownTag"));
-		TIMESTAMP = p
-				.getProperty("tavernaserver.timestamp", "unknownTimestamp");
-	}
-
-	public VersionedElement() {
-	}
-
-	protected VersionedElement(boolean ignored) {
-		serverVersion = VERSION;
-		serverRevision = REVISION;
-		serverBuildTimestamp = TIMESTAMP;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java b/server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
deleted file mode 100644
index ba6a68c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/Workflow.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common;
-
-import static javax.xml.bind.Marshaller.JAXB_ENCODING;
-import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
-import static javax.xml.bind.annotation.XmlAccessType.NONE;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Serializable;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.net.URL;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlAnyElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.taverna.server.master.rest.handler.Scufl2DocumentHandler;
-import org.taverna.server.master.rest.handler.T2FlowDocumentHandler;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
-
-import uk.org.taverna.scufl2.api.common.NamedSet;
-import uk.org.taverna.scufl2.api.container.WorkflowBundle;
-import uk.org.taverna.scufl2.api.io.ReaderException;
-import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
-import uk.org.taverna.scufl2.api.io.WriterException;
-import uk.org.taverna.scufl2.api.profiles.Profile;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * Encapsulation of a T2flow or Scufl2 document.
- * 
- * @author Donal K. Fellows
- */
-@XmlRootElement(name = "workflow")
-@XmlType(name = "Workflow")
-@XmlAccessorType(NONE)
-public class Workflow implements Serializable, Externalizable {
-	/** Literal document, if present. */
-	@XmlAnyElement(lax = true)
-	private Element content;
-	/** SCUFL2 bundle, if present. */
-	@XmlTransient
-	private WorkflowBundle bundle;
-	/** Which came first, the bundle or the t2flow document. */
-	@XmlTransient
-	private boolean isBundleFirst;
-
-	private static Marshaller marshaller;
-	private static Unmarshaller unmarshaller;
-	private final static String ENCODING = "UTF-8";
-	private final static WorkflowBundleIO io;
-	static {
-		try {
-			JAXBContext context = JAXBContext.newInstance(Workflow.class);
-			marshaller = context.createMarshaller();
-			unmarshaller = context.createUnmarshaller();
-			marshaller.setProperty(JAXB_ENCODING, ENCODING);
-			marshaller.setProperty(JAXB_FORMATTED_OUTPUT, false);
-		} catch (JAXBException e) {
-			getLog("Taverna.Server.Webapp").fatal(
-					"failed to build JAXB context for working with "
-							+ Workflow.class, e);
-		}
-		io = new WorkflowBundleIO();
-	}
-
-	public enum ContentType {
-		T2FLOW(T2FlowDocumentHandler.T2FLOW), SCUFL2(
-				Scufl2DocumentHandler.SCUFL2);
-		private String type;
-
-		ContentType(String type) {
-			this.type = type;
-		}
-
-		public String getContentType() {
-			return type;
-		}
-	}
-
-	public Workflow() {
-	}
-
-	public Workflow(Element element) {
-		this.content = element;
-		this.isBundleFirst = false;
-	}
-
-	public Workflow(WorkflowBundle bundle) {
-		this.bundle = bundle;
-		this.isBundleFirst = true;
-	}
-
-	public Workflow(URL url) throws ReaderException, IOException {
-		this(io.readBundle(url, null));
-	}
-
-	/**
-	 * What content type would this workflow "prefer" to be?
-	 */
-	public ContentType getPreferredContentType() {
-		if (isBundleFirst)
-			return ContentType.SCUFL2;
-		else
-			return ContentType.T2FLOW;
-	}
-
-	/**
-	 * Retrieves the workflow as a SCUFL2 document, converting it if necessary.
-	 * 
-	 * @return The SCUFL2 document.
-	 * @throws IOException
-	 *             If anything goes wrong.
-	 */
-	public WorkflowBundle getScufl2Workflow() throws IOException {
-		try {
-			if (bundle == null)
-				bundle = io.readBundle(new ByteArrayInputStream(getAsT2Flow()),
-						T2FLOW);
-			return bundle;
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException("problem when converting to SCUFL2", e);
-		}
-	}
-
-	/**
-	 * Get the bytes of the serialized SCUFL2 workflow.
-	 * 
-	 * @return Array of bytes.
-	 * @throws IOException
-	 *             If serialization fails.
-	 * @throws WriterException
-	 *             If conversion fails.
-	 */
-	public byte[] getScufl2Bytes() throws IOException, WriterException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		io.writeBundle(getScufl2Workflow(), baos, SCUFL2);
-		return baos.toByteArray();
-	}
-
-	/**
-	 * Retrieves the workflow as a T2Flow document, converting it if necessary.
-	 * 
-	 * @return The T2Flow document.
-	 * @throws IOException
-	 *             If anything goes wrong.
-	 */
-	public Element getT2flowWorkflow() throws IOException {
-		try {
-			if (content != null)
-				return content;
-			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			io.writeBundle(bundle, baos, T2FLOW);
-			Document doc;
-			try {
-				DocumentBuilderFactory dbf = DocumentBuilderFactory
-						.newInstance();
-				dbf.setNamespaceAware(true);
-				doc = dbf.newDocumentBuilder().parse(
-						new ByteArrayInputStream(baos.toByteArray()));
-			} catch (SAXException e) {
-				throw new IOException("failed to convert to DOM tree", e);
-			}
-			Element e = doc.getDocumentElement();
-			if (e.getNamespaceURI().equals(T2FLOW_NS)
-					&& e.getNodeName().equals(T2FLOW_ROOTNAME))
-				return content = e;
-			throw new IOException(
-					"unexpected element when converting to T2Flow: {"
-							+ e.getNamespaceURI() + "}" + e.getNodeName());
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException("problem when converting to SCUFL2", e);
-		}
-	}
-
-	/**
-	 * @return The name of the main workflow profile, or <tt>null</tt> if there
-	 *         is none.
-	 */
-	public String getMainProfileName() {
-		try {
-			return getScufl2Workflow().getMainProfile().getName();
-		} catch (IOException e) {
-			return null;
-		}
-	}
-
-	/**
-	 * @return The set of profiles supported over this workflow.
-	 */
-	public NamedSet<Profile> getProfiles() {
-		try {
-			return getScufl2Workflow().getProfiles();
-		} catch (IOException e) {
-			return new NamedSet<Profile>();
-		}
-	}
-
-	/**
-	 * Convert from marshalled form.
-	 * 
-	 * @throws JAXBException
-	 *             If the conversion fails.
-	 */
-	public static Workflow unmarshal(String representation)
-			throws JAXBException {
-		StringReader sr = new StringReader(representation);
-		return (Workflow) unmarshaller.unmarshal(sr);
-	}
-
-	/**
-	 * Convert to marshalled form.
-	 */
-	public String marshal() throws JAXBException {
-		StringWriter sw = new StringWriter();
-		marshaller.marshal(this, sw);
-		return sw.toString();
-	}
-
-	@Override
-	public void readExternal(ObjectInput in) throws IOException,
-			ClassNotFoundException {
-		try {
-			ByteArrayInputStream bytes = readbytes(in);
-			if (bytes != null)
-				try (Reader r = new InputStreamReader(bytes, ENCODING)) {
-					content = ((Workflow) unmarshaller.unmarshal(r)).content;
-				}
-			bytes = readbytes(in);
-			if (bytes != null)
-				bundle = io.readBundle(bytes, SCUFL2);
-			isBundleFirst = in.readBoolean();
-			return;
-		} catch (JAXBException e) {
-			throw new IOException("failed to unmarshal", e);
-		} catch (ClassCastException e) {
-			throw new IOException("bizarre result of unmarshalling", e);
-		} catch (ReaderException e) {
-			throw new IOException("failed to unmarshal", e);
-		}
-	}
-
-	private byte[] getAsT2Flow() throws IOException, JAXBException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		OutputStreamWriter w = new OutputStreamWriter(baos, ENCODING);
-		marshaller.marshal(this, w);
-		w.close();
-		return baos.toByteArray();
-	}
-
-	private byte[] getAsScufl2() throws IOException, WriterException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		io.writeBundle(bundle, baos, SCUFL2);
-		baos.close();
-		return baos.toByteArray();
-	}
-
-	@Override
-	public void writeExternal(ObjectOutput out) throws IOException {
-		try {
-			writebytes(out, (content != null) ? getAsT2Flow() : null);
-		} catch (JAXBException e) {
-			throw new IOException("failed to marshal t2flow", e);
-		}
-		try {
-			writebytes(out, (bundle != null) ? getAsScufl2() : null);
-		} catch (WriterException e) {
-			throw new IOException("failed to marshal scufl2", e);
-		}
-		out.writeBoolean(isBundleFirst);
-	}
-
-	private ByteArrayInputStream readbytes(ObjectInput in) throws IOException {
-		int len = in.readInt();
-		if (len > 0) {
-			byte[] bytes = new byte[len];
-			in.readFully(bytes);
-			return new ByteArrayInputStream(bytes);
-		}
-		return null;
-	}
-
-	private void writebytes(ObjectOutput out, byte[] data) throws IOException {
-		out.writeInt(data == null ? 0 : data.length);
-		if (data != null && data.length > 0)
-			out.write(data);
-	}
-
-	/**
-	 * Make up for the lack of an integrated XPath engine.
-	 * 
-	 * @param name
-	 *            The element names to look up from the root of the contained
-	 *            document.
-	 * @return The looked up element, or <tt>null</tt> if it doesn't exist.
-	 */
-	private Element getEl(String... name) {
-		Element el = content;
-		boolean skip = true;
-		for (String n : name) {
-			if (skip) {
-				skip = false;
-				continue;
-			}
-			if (el == null)
-				return null;
-			NodeList nl = el.getElementsByTagNameNS(T2FLOW_NS, n);
-			if (nl.getLength() == 0)
-				return null;
-			Node node = nl.item(0);
-			if (node instanceof Element)
-				el = (Element) node;
-			else
-				return null;
-		}
-		return el;
-	}
-
-	/**
-	 * @return The content of the embedded
-	 *         <tt>&lt;workflow&gt;&lt;dataflow&gt;&lt;name&gt;</tt> element.
-	 */
-	@XmlTransient
-	public String getName() {
-		return getEl("workflow", "dataflow", "name").getTextContent();
-	}
-
-	/**
-	 * @return The embedded <tt>&lt;workflow&gt;</tt> element.
-	 */
-	@XmlTransient
-	public Element getWorkflowRoot() {
-		return getEl("workflow");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
deleted file mode 100644
index fd040de..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/package-info.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the common XML elements used throughout Taverna Server's various interfaces.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.common;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java b/server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
deleted file mode 100644
index e9c58a9..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/common/version/Version.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.common.version;
-
-import static org.taverna.server.master.common.version.Constants.PATCH;
-import static org.taverna.server.master.common.version.Constants.VERSION;
-
-/**
- * Common location for describing the version of the server.
- * 
- * @author Donal Fellows
- */
-public interface Version {
-	public static final String JAVA = VERSION + Constants.releaseChar + PATCH;
-	public static final String HTML = VERSION + Constants.releaseHEnt + PATCH;
-	public static final String XML = VERSION + Constants.releaseXEnt + PATCH;
-}
-
-/**
- * The pieces of a version string.
- * 
- * @author Donal Fellows
- */
-interface Constants {
-	static final String MAJOR = "2";
-	static final String MINOR = "5";
-	static final String PATCH = "4";
-
-	static final char alphaChar = '\u03b1';
-	static final char betaChar = '\u03b2';
-	static final char releaseChar = '.';
-	static final String alphaHEnt = "&alpha;";
-	static final String betaHEnt = "&beta;";
-	static final String releaseHEnt = ".";
-	static final String alphaXEnt = "&#x03b1;";
-	static final String betaXEnt = "&#x03b2;";
-	static final String releaseXEnt = ".";
-
-	static final String VERSION = MAJOR + "." + MINOR;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java b/server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
deleted file mode 100644
index c2a2bc9..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/defaults/Default.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.defaults;
-
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.localworker.LocalWorkerState;
-
-/**
- * This defines a collection of default values, collecting them from various
- * parts of the server.
- * 
- * @author Donal Fellows
- */
-public interface Default {
-	/** The default value of the <tt>prefix</tt> property. */
-	static final String AUTHORITY_PREFIX = "LOCALUSER_";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that this class will fork off.
-	 */
-	static final String SERVER_WORKER_IMPLEMENTATION_JAR = "util/server.worker.jar";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that manages secure forking.
-	 */
-	static final String SECURE_FORK_IMPLEMENTATION_JAR = "util/secure.fork.jar";
-
-	/**
-	 * The name of the resource that is the implementation of the subprocess
-	 * that acts as the RMI registry.
-	 */
-	static final String REGISTRY_JAR = "util/rmi.daemon.jar";
-
-	/** Initial lifetime of runs, in minutes. */
-	static final int RUN_LIFE_MINUTES = 20;
-
-	/**
-	 * Maximum number of runs to exist at once. Note that this includes when
-	 * they are just existing for the purposes of file transfer (
-	 * {@link Status#Initialized}/{@link Status#Finished} states).
-	 */
-	static final int RUN_COUNT_MAX = 5;
-
-	/**
-	 * Prefix to use for RMI names.
-	 */
-	static final String RMI_PREFIX = "ForkRunFactory.";
-
-	/** Default value for {@link LocalWorkerState#passwordFile}. */
-	static final String PASSWORD_FILE = null;
-
-	/**
-	 * The extra arguments to pass to the subprocess.
-	 */
-	static final String[] EXTRA_ARGUMENTS = new String[0];
-
-	/**
-	 * How long to wait for subprocess startup, in seconds.
-	 */
-	static final int SUBPROCESS_START_WAIT = 40;
-
-	/**
-	 * Polling interval to use during startup, in milliseconds.
-	 */
-	static final int SUBPROCESS_START_POLL_SLEEP = 1000;
-
-	/**
-	 * Maximum number of {@link Status#Operating} runs at any time.
-	 */
-	static final int RUN_OPERATING_LIMIT = 10;
-
-	/**
-	 * What fields of a certificate we look at when understanding who it is
-	 * talking about, in the order that we look.
-	 */
-	static final String[] CERTIFICATE_FIELD_NAMES = { "CN", "COMMONNAME",
-			"COMMON NAME", "COMMON_NAME", "OU", "ORGANIZATIONALUNITNAME",
-			"ORGANIZATIONAL UNIT NAME", "O", "ORGANIZATIONNAME",
-			"ORGANIZATION NAME" };
-
-	/** The type of certificates that are processed if we don't say otherwise. */
-	static final String CERTIFICATE_TYPE = "X.509";
-
-	/** Max size of credential file, in kiB. */
-	static final int CREDENTIAL_FILE_SIZE_LIMIT = 20;
-
-	/**
-	 * The notification message format to use if none is configured.
-	 */
-	public static final String NOTIFY_MESSAGE_FORMAT = "Your job with ID={0} has finished with exit code {1,number,integer}.";
-
-	/** The address of the SMS gateway service used. */
-	public static final String SMS_GATEWAY_URL = "https://www.intellisoftware.co.uk/smsgateway/sendmsg.aspx";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
deleted file mode 100644
index 239b260..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/defaults/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * This package contains information about the various default values supported by the server.
- * @author Donal Fellows
- */
-package org.taverna.server.master.defaults;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
deleted file mode 100644
index 0b6247e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadInputPortNameException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates that the port name was not recognized.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "BadInputPortNameFault")
-@SuppressWarnings("serial")
-public class BadInputPortNameException extends Exception {
-	public BadInputPortNameException(String msg) {
-		super(msg);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
deleted file mode 100644
index 303b19b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadPropertyValueException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates a bad property value.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "BadPropertyValueFault")
-public class BadPropertyValueException extends NoListenerException {
-	private static final long serialVersionUID = -8459491388504556875L;
-
-	public BadPropertyValueException(String msg) {
-		super(msg);
-	}
-
-	public BadPropertyValueException(String msg, Throwable e) {
-		super(msg, e);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
deleted file mode 100644
index 4b843e2..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/BadStateChangeException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the state change requested for a
- * run is impossible.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoUpdateFault")
-public class BadStateChangeException extends NoUpdateException {
-	private static final long serialVersionUID = -4490826388447601775L;
-
-	public BadStateChangeException() {
-		super("cannot do that state change");
-	}
-
-	public BadStateChangeException(Throwable t) {
-		super("cannot do that state change", t);
-	}
-
-	public BadStateChangeException(String msg, Throwable t) {
-		super(msg, t);
-	}
-
-	public BadStateChangeException(String message) {
-		super(message);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
deleted file mode 100644
index 0b6cf07..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/FilesystemAccessException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import java.rmi.RemoteException;
-
-import javax.xml.ws.WebFault;
-
-/**
- * An exception that happened when the underlying filesystem was accessed.
- * @author Donal Fellows
- */
-@WebFault(name = "FilesystemAccessFault")
-public class FilesystemAccessException extends Exception {
-	private static final long serialVersionUID = 8715937300989820318L;
-
-	public FilesystemAccessException(String msg) {
-		super(msg);
-	}
-
-	public FilesystemAccessException(String string, Throwable cause) {
-		super(string, getRealCause(cause));
-	}
-
-	private static Throwable getRealCause(Throwable t) {
-		if (t instanceof RemoteException) {
-			RemoteException remote = (RemoteException) t;
-			if (remote.detail != null)
-				return remote.detail;
-		}
-		if (t.getCause() != null)
-			return t.getCause();
-		return t;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
deleted file mode 100644
index 11d47c7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/GeneralFailureException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Some sort of exception that occurred which we can't map any other way. This
- * is generally indicative of a problem server-side.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "GeneralFailureFault", targetNamespace = SERVER_SOAP)
-@SuppressWarnings("serial")
-public class GeneralFailureException extends RuntimeException {
-	public GeneralFailureException(Throwable cause) {
-		super(cause.getMessage(), cause);
-	}
-
-	public GeneralFailureException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
deleted file mode 100644
index 67ba551..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/InvalidCredentialException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-/**
- * An exception that is thrown to indicate that a credential-descriptor or
- * trust-descriptor supplied as part of a credential or trust management
- * operation is invalid.
- * 
- * @author Donal Fellows
- * 
- */
-@SuppressWarnings("serial")
-public class InvalidCredentialException extends Exception {
-	private static final String MSG = "that credential is invalid";
-
-	public InvalidCredentialException() {
-		super(MSG);
-	}
-
-	public InvalidCredentialException(String reason) {
-		super(MSG + ": " + reason);
-	}
-
-	public InvalidCredentialException(String reason, Throwable cause) {
-		this(reason);
-		initCause(cause);
-	}
-
-	public InvalidCredentialException(Throwable cause) {
-		this(cause.getMessage(), cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
deleted file mode 100644
index e2ddf4c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCreateException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to
- * create something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoCreateFault")
-public class NoCreateException extends NoUpdateException {
-	private static final long serialVersionUID = 270413810410167235L;
-
-	public NoCreateException() {
-		super("not permitted to create");
-	}
-
-	public NoCreateException(String string) {
-		super(string);
-	}
-
-	public NoCreateException(String string, Throwable e) {
-		super(string, e);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
deleted file mode 100644
index 7077fc4..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoCredentialException.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-/**
- * Exception that indicates the absence of an expected credential.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class NoCredentialException extends Exception {
-	public NoCredentialException() {
-		super("no such credential");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
deleted file mode 100644
index d7b0d29..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDestroyException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to
- * destroy something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoDestroyFault")
-public class NoDestroyException extends NoUpdateException {
-	private static final long serialVersionUID = 6207448533265237933L;
-
-	public NoDestroyException() {
-		super("not permitted to destroy");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
deleted file mode 100644
index 0d6ca63..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoDirectoryEntryException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Indicates that the file or directory name was not recognized.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoDirectoryEntryFault")
-@SuppressWarnings("serial")
-public class NoDirectoryEntryException extends Exception {
-	public NoDirectoryEntryException(String msg) {
-		super(msg);
-	}
-	public NoDirectoryEntryException(String msg,Exception cause) {
-		super(msg, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
deleted file mode 100644
index f4b8e81..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoListenerException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.ws.WebFault;
-
-/**
- * Exception thrown to indicate that no listener by that name exists, or that
- * some other problem with listeners has occurred.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoListenerFault")
-@XmlSeeAlso(BadPropertyValueException.class)
-public class NoListenerException extends Exception {
-	private static final long serialVersionUID = -2550897312787546547L;
-
-	public NoListenerException() {
-		super("no such listener");
-	}
-
-	public NoListenerException(String msg) {
-		super(msg);
-	}
-
-	public NoListenerException(String msg, Throwable t) {
-		super(msg, t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
deleted file mode 100644
index c49d111..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NoUpdateException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the user is not permitted to update
- * something.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NoUpdateFault")
-@XmlSeeAlso( { NoCreateException.class, NoDestroyException.class, BadStateChangeException.class })
-public class NoUpdateException extends Exception {
-	private static final long serialVersionUID = 4230987102653846379L;
-
-	public NoUpdateException() {
-		super("not permitted to update");
-	}
-
-	public NoUpdateException(String msg) {
-		super(msg);
-	}
-
-	public NoUpdateException(String string, Throwable e) {
-		super(string, e);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
deleted file mode 100644
index 6e1f792..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/NotOwnerException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * An exception thrown when an operation is attempted which only the owner is
- * permitted to do. Notably, permissions may <i>only</i> be manipulated by the
- * owner.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "NotOwnerFault")
-@SuppressWarnings("serial")
-public class NotOwnerException extends Exception {
-	public NotOwnerException() {
-		super("not permitted; not the owner");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
deleted file mode 100644
index dda371e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/OverloadedException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that is thrown to indicate that the state change requested for a
- * run is currently impossible due to excessive server load.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "OverloadedFault")
-public class OverloadedException extends BadStateChangeException {
-	private static final long serialVersionUID = 490826388447601776L;
-
-	public OverloadedException() {
-		super("server too busy; try later please");
-	}
-
-	public OverloadedException(Throwable t) {
-		super("server too busy; try later please", t);
-	}
-
-	public OverloadedException(String msg, Throwable t) {
-		super(msg, t);
-	}
-
-	public OverloadedException(String message) {
-		super(message);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
deleted file mode 100644
index 4632d4a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/UnknownRunException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.exceptions;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception thrown to indicate that the handle of the run is unknown (or
- * unacceptable to the current user).
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "UnknownRunFault")
-public class UnknownRunException extends Exception {
-	private static final long serialVersionUID = -3028749401786242841L;
-
-	public UnknownRunException() {
-		super("unknown run UUID");
-	}
-
-	public UnknownRunException(Throwable t) {
-		super("implementation problems", t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
deleted file mode 100644
index 29ccacd..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/exceptions/package-info.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the exceptions/faults thrown by Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.exceptions;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java b/server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
deleted file mode 100644
index 0015754..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/facade/Facade.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.facade;
-
-import static javax.ws.rs.core.MediaType.TEXT_HTML_TYPE;
-import static javax.ws.rs.core.Response.ok;
-
-import java.io.IOException;
-import java.net.URL;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.utils.Contextualizer;
-
-/**
- * This is a simple class that is used to serve up a file (with a simple
- * substitution applied) as the root of the T2Server webapp.
- * 
- * @author Donal Fellows
- */
-@Path("/")
-public class Facade {
-	private Log log = LogFactory.getLog("Taverna.Server.Utils");
-	private String welcome;
-	private Contextualizer contextualizer;
-
-	/**
-	 * Set what resource file to use as the template for the response.
-	 * 
-	 * @param file
-	 *            The file from which to load the data (presumed HTML) to serve
-	 *            up as the root content.
-	 * @throws IOException
-	 *             If the file doesn't exist.
-	 */
-	public void setFile(String file) throws IOException {
-		URL full = Facade.class.getResource(file);
-		log.info("setting " + full + " as source of root page");
-		this.welcome = IOUtils.toString(full);
-	}
-
-	@Required
-	public void setContextualizer(Contextualizer contextualizer) {
-		this.contextualizer = contextualizer;
-	}
-
-	/**
-	 * Serve up some HTML as the root of the service.
-	 * 
-	 * @param ui
-	 *            A reference to how we were accessed by the service.
-	 * @return The response, containing the HTML.
-	 */
-	@GET
-	@Path("{dummy:.*}")
-	@Produces("text/html")
-	public Response get(@Context UriInfo ui) {
-		return ok(contextualizer.contextualize(ui, welcome), TEXT_HTML_TYPE)
-				.build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
deleted file mode 100644
index 73c884f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/facade/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Simple facade used at the top level of the Taverna Server in order to
- * provide an entry splash page.
- */
-package org.taverna.server.master.facade;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java b/server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
deleted file mode 100644
index 954b6f1..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/factories/ConfigurableRunFactory.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.factories;
-
-/**
- * Interface to run factories for the purpose of configuration.
- * 
- * @author Donal Fellows
- */
-public interface ConfigurableRunFactory extends RunFactory {
-	/** Where is the registry? Getter */
-	String getRegistryHost();
-
-	/** Where is the registry? Setter */
-	void setRegistryHost(String host);
-
-	/** Where is the registry? Getter */
-	int getRegistryPort();
-
-	/** Where is the registry? Setter */
-	void setRegistryPort(int port);
-
-	/** How much can be done at once? Getter */
-	int getMaxRuns();
-
-	/** How much can be done at once? Setter */
-	void setMaxRuns(int maxRuns);
-
-	/** How long will things live? Getter */
-	int getDefaultLifetime();
-
-	/** How long will things live? Setter */
-	void setDefaultLifetime(int defaultLifetime);
-
-	/** How often do we probe for info? Getter */
-	int getSleepTime();
-
-	/** How often do we probe for info? Setter */
-	void setSleepTime(int sleepTime);
-
-	/** How long do we allow for actions? Getter */
-	int getWaitSeconds();
-
-	/** How long do we allow for actions? Setter */
-	void setWaitSeconds(int seconds);
-
-	/** How do we start the workflow engine? Getter */
-	String getExecuteWorkflowScript();
-
-	/** How do we start the workflow engine? Setter */
-	void setExecuteWorkflowScript(String executeWorkflowScript);
-
-	/** How do we start the file system access process? Getter */
-	String getServerWorkerJar();
-
-	/** How do we start the file system access process? Setter */
-	void setServerWorkerJar(String serverWorkerJar);
-
-	/**
-	 * How do we start the file system access process? Extra arguments to pass.
-	 * Getter
-	 */
-	String[] getExtraArguments();
-
-	/**
-	 * How do we start the file system access process? Extra arguments to pass.
-	 * Setter
-	 */
-	void setExtraArguments(String[] firstArguments);
-
-	/** Where is Java? Getter */
-	String getJavaBinary();
-
-	/** Where is Java? Setter */
-	void setJavaBinary(String javaBinary);
-
-	/** Where do we get passwords from? Getter */
-	String getPasswordFile();
-
-	/** Where do we get passwords from? Setter */
-	void setPasswordFile(String newValue);
-
-	/** How do we switch users? Getter */
-	String getServerForkerJar();
-
-	/** How do we switch users? Setter */
-	void setServerForkerJar(String newValue);
-
-	/** How many runs have there been? */
-	int getTotalRuns();
-
-	/** How long did the last subprocess startup take? */
-	int getLastStartupCheckCount();
-
-	/** What are the current runs? */
-	String[] getCurrentRunNames();
-
-	/** What is the RMI ID of the factory process? */
-	String getFactoryProcessName();
-
-	/** What was the last observed exit code? */
-	Integer getLastExitCode();
-
-	/** What factory process to use for a particular user? */
-	String[] getFactoryProcessMapping();
-
-	/** How many runs can be operating at once? Setter */
-	void setOperatingLimit(int operatingLimit);
-
-	/** How many runs can be operating at once? Getter */
-	int getOperatingLimit();
-
-	/**
-	 * How many runs are actually operating?
-	 * 
-	 * @throws Exception
-	 *             if anything goes wrong
-	 */
-	int getOperatingCount() throws Exception;
-
-	/** How do we start the RMI registry process? Getter */
-	String getRmiRegistryJar();
-
-	/** How do we start the RMI registry process? Setter */
-	void setRmiRegistryJar(String rmiRegistryJar);
-
-	boolean getGenerateProvenance();
-
-	void setGenerateProvenance(boolean generateProvenance);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java b/server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
deleted file mode 100644
index ecc13cd..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/factories/ListenerFactory.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.factories;
-
-import java.util.List;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * How to make event listeners of various types that are attached to a workflow
- * instance.
- * 
- * @author Donal Fellows
- */
-public interface ListenerFactory {
-	/**
-	 * Make an event listener.
-	 * 
-	 * @param run
-	 *            The workflow instance to attach the event listener to.
-	 * @param listenerType
-	 *            The type of event listener to create. Must be one of the
-	 *            strings returned by {@link #getSupportedListenerTypes()}.
-	 * @param configuration
-	 *            A configuration document to pass to the listener.
-	 * @return The event listener that was created.
-	 * @throws NoListenerException
-	 *             If the <b>listenerType</b> is unrecognized or the
-	 *             <b>configuration</b> is bad in some way.
-	 */
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException;
-
-	/**
-	 * What types of listener are supported? Note that we assume that the list
-	 * of types is the same for all users and all workflow instances.
-	 * 
-	 * @return A list of supported listener types.
-	 */
-	public List<String> getSupportedListenerTypes();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java b/server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
deleted file mode 100644
index eeacad7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/factories/RunFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.factories;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * How to construct a Taverna Server Workflow Run.
- * 
- * @author Donal Fellows
- */
-public interface RunFactory {
-	/**
-	 * Make a Taverna Server workflow run that is bound to a particular user
-	 * (the "creator") and able to run a particular workflow.
-	 * 
-	 * @param creator
-	 *            The user creating the workflow instance.
-	 * @param workflow
-	 *            The workflow to instantiate
-	 * @return An object representing the run.
-	 * @throws NoCreateException
-	 *             On failure.
-	 */
-	TavernaRun create(UsernamePrincipal creator, Workflow workflow)
-			throws NoCreateException;
-
-	/**
-	 * Check whether the factory is permitting runs to actually start operating.
-	 * 
-	 * @return Whether a run should start.
-	 */
-	boolean isAllowingRunsToStart();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
deleted file mode 100644
index 39b9ac6..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/factories/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * These interfaces define the principal way for the <i>factories</i> of
- * worker classes to be invoked.
- */
-package org.taverna.server.master.factories;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java b/server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
deleted file mode 100644
index 63402ef..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/AuthorityDerivedIDMapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static org.taverna.server.master.defaults.Default.AUTHORITY_PREFIX;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Extracts the local user id from the set of Spring Security authorities
- * granted to the current user. This is done by scanning the set of authorities
- * to see if any of them start with the substring listed in the <tt>prefix</tt>
- * property; the username is the rest of the authority string in that case.
- * 
- * @author Donal Fellows
- */
-public class AuthorityDerivedIDMapper implements LocalIdentityMapper {
-	private String prefix = AUTHORITY_PREFIX;
-
-	public String getPrefix() {
-		return prefix;
-	}
-
-	public void setPrefix(String prefix) {
-		this.prefix = prefix;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		Authentication auth = SecurityContextHolder.getContext()
-				.getAuthentication();
-		if (auth == null || !auth.isAuthenticated())
-			return null;
-		for (GrantedAuthority authority : auth.getAuthorities()) {
-			String token = authority.getAuthority();
-			if (token == null)
-				continue;
-			if (token.startsWith(prefix))
-				return token.substring(prefix.length());
-		}
-		return null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java b/server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
deleted file mode 100644
index b5fcd5a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/CompositeIDMapper.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * An identity mapper that composes the results from other mappers, using the
- * identity mappers in order until one can provide a non-<tt>null</tt> answer.
- * 
- * @author Donal Fellows.
- */
-public class CompositeIDMapper implements LocalIdentityMapper,
-		ApplicationContextAware {
-	private Log log = getLog("Taverna.Server.IdentityMapper");
-	private List<LocalIdentityMapper> mappers;
-	private ApplicationContext context;
-
-	/**
-	 * @param mappers
-	 *            The list of mappers to delegate to. Order is significant.
-	 */
-	public void setIdentityMappers(List<LocalIdentityMapper> mappers) {
-		this.mappers = mappers;
-	}
-
-	@Override
-	public void setApplicationContext(ApplicationContext applicationContext)
-			throws BeansException {
-		context = applicationContext;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		if (mappers == null)
-			return null;
-		for (LocalIdentityMapper m : mappers) {
-			String u = m.getUsernameForPrincipal(user);
-			if (u == null)
-				continue;
-			for (Entry<String, ? extends LocalIdentityMapper> entry : context
-					.getBeansOfType(m.getClass()).entrySet())
-				if (m == entry.getValue()) {
-					log.info("used " + entry.getKey() + " LIM to map " + user
-							+ " to " + u);
-					break;
-				}
-			return u;
-		}
-		return null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java b/server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
deleted file mode 100644
index e81f926..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/ConstantIDMapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A trivial principal to user mapper that always uses the same ID.
- * @author Donal Fellows
- */
-public class ConstantIDMapper implements LocalIdentityMapper {
-	private String id;
-
-	/**
-	 * Sets what local user ID all users should be mapped to.
-	 * 
-	 * @param id
-	 *            The local user ID.
-	 */
-	public void setConstantId(String id) {
-		this.id = id;
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		return id;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java b/server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
deleted file mode 100644
index 42a3874..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/identity/NameIDMapper.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.identity;
-
-import static java.util.regex.Pattern.compile;
-
-import java.security.Principal;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A trivial identity mapper that just uses the name out of the
- * {@link Principal}, or uses a regular expression to extract it from the string
- * representation of the principal.
- * 
- * @author Donal Fellows
- */
-public class NameIDMapper implements LocalIdentityMapper {
-	private Pattern pat;
-
-	/**
-	 * @param regexp
-	 *            The regular expression to use. The first capturing group
-	 *            within the RE will be the result of the extraction.
-	 * @throws PatternSyntaxException
-	 *             If the pattern is invalid.
-	 */
-	public void setRegexp(String regexp) throws PatternSyntaxException {
-		pat = compile(regexp);
-	}
-
-	@Override
-	public String getUsernameForPrincipal(UsernamePrincipal user) {
-		if (pat != null) {
-			Matcher m = pat.matcher(user.toString());
-			if (m.find() && m.groupCount() > 0) {
-				return m.group(1);
-			}
-			return null;
-		}
-		return user.getName();
-	}
-}


[34/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java b/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
deleted file mode 100644
index aead6fa..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.String.format;
-import static java.lang.System.nanoTime;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Logs the time it takes to service HTTP calls into Taverna Server.
- * <p>
- * This class is currently not used.
- * 
- * @author Donal Fellows
- */
-public class CallTimingFilter implements Filter {
-	private Log log;
-	private String name;
-
-	@Override
-	public void init(FilterConfig filterConfig) throws ServletException {
-		log = getLog("Taverna.Server.Performance");
-		name = filterConfig.getInitParameter("name");
-	}
-
-	@Override
-	public void doFilter(ServletRequest request, ServletResponse response,
-			FilterChain chain) throws IOException, ServletException {
-		if (request instanceof HttpServletRequest)
-			doFilter((HttpServletRequest) request,
-					(HttpServletResponse) response, chain);
-		else
-			chain.doFilter(request, response);
-	}
-
-	public void doFilter(HttpServletRequest request,
-			HttpServletResponse response, FilterChain chain)
-			throws IOException, ServletException {
-		long start = nanoTime();
-		chain.doFilter(request, response);
-		long elapsedTime = nanoTime() - start;
-		log.info(format("%s call to %s %s took %.3fms", name,
-				request.getMethod(), request.getRequestURI(),
-				elapsedTime / 1000000.0));
-	}
-
-	@Override
-	public void destroy() {
-		log = null;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java b/server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
deleted file mode 100644
index 54b0420..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.taverna.server.master.utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import javax.annotation.PostConstruct;
-
-import org.taverna.server.master.common.Capability;
-
-/**
- * Utility for listing the capabilities supported by this Taverna Server
- * installation.
- * 
- * @author Donal Fellows
- */
-public class CapabilityLister {
-	public static final String CAPABILITY_RESOURCE_FILE = "/capabilities.properties";
-	private Properties properties = new Properties();
-
-	@PostConstruct
-	void loadCapabilities() throws IOException {
-		try (InputStream is = getClass().getResourceAsStream(
-				CAPABILITY_RESOURCE_FILE)) {
-			if (is != null)
-				properties.load(is);
-		}
-	}
-
-	public List<Capability> getCapabilities() {
-		List<Capability> caps = new ArrayList<>();
-		for (Entry<Object, Object> entry : properties.entrySet()) {
-			Capability c = new Capability();
-			c.capability = URI.create(entry.getKey().toString());
-			c.version = entry.getValue().toString();
-			caps.add(c);
-		}
-		return caps;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java b/server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
deleted file mode 100644
index c27502f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableList;
-
-import java.io.IOException;
-import java.net.URI;
-import java.security.GeneralSecurityException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-import javax.xml.ws.Holder;
-
-/**
- * Obtains the certificate chain for an arbitrary SSL service. Maintains a
- * cache.
- * 
- * @author Donal Fellows
- */
-public class CertificateChainFetcher {
-	public String getProtocol() {
-		return protocol;
-	}
-
-	public void setProtocol(String protocol) {
-		this.protocol = protocol;
-	}
-
-	public String getKeystoreType() {
-		return keystoreType;
-	}
-
-	public void setKeystoreType(String keystoreType) {
-		this.keystoreType = keystoreType;
-	}
-
-	public String getAlgorithm() {
-		return algorithm;
-	}
-
-	public void setAlgorithm(String algorithm) {
-		this.algorithm = algorithm;
-	}
-
-	public int getTimeout() {
-		return timeout;
-	}
-
-	public void setTimeout(int timeout) {
-		this.timeout = timeout;
-	}
-
-	public void setSecure(boolean secure) {
-		this.secure = secure;
-	}
-
-	private boolean secure = true;
-	private String protocol = "TLS";
-	private String keystoreType = KeyStore.getDefaultType();
-	private String algorithm = TrustManagerFactory.getDefaultAlgorithm();
-	private int timeout = 10000;
-
-	/**
-	 * Get the certificate chain for a service.
-	 * 
-	 * @param host
-	 *            The host (name or IP address) to contact the service on.
-	 * @param port
-	 *            The port to contact the service on.
-	 * @return The certificate chain, or <tt>null</tt> if no credentials are
-	 *         available.
-	 * @throws NoSuchAlgorithmException
-	 *             If the trust manager cannot be set up because of algorithm
-	 *             problems.
-	 * @throws KeyStoreException
-	 *             If the trust manager cannot be set up because of problems
-	 *             with the keystore type.
-	 * @throws CertificateException
-	 *             If a bad certificate is present in the default keystore;
-	 *             <i>should be impossible</i>.
-	 * @throws IOException
-	 *             If problems happen when trying to contact the service.
-	 * @throws KeyManagementException
-	 *             If the SSL context can't have its special context manager
-	 *             installed.
-	 */
-	private X509Certificate[] getCertificateChainForService(String host,
-			int port) throws NoSuchAlgorithmException, KeyStoreException,
-			CertificateException, IOException, KeyManagementException {
-		KeyStore ks = KeyStore.getInstance(keystoreType);
-		SSLContext context = SSLContext.getInstance(protocol);
-		TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
-		ks.load(null, null);
-		tmf.init(ks);
-		final Holder<X509Certificate[]> chain = new Holder<>();
-		final X509TrustManager defaultTrustManager = (X509TrustManager) tmf
-				.getTrustManagers()[0];
-		context.init(null, new TrustManager[] { new X509TrustManager() {
-			@Override
-			public void checkClientTrusted(X509Certificate[] clientChain,
-					String authType) throws CertificateException {
-				throw new UnsupportedOperationException();
-			}
-
-			@Override
-			public void checkServerTrusted(X509Certificate[] serverChain,
-					String authType) throws CertificateException {
-				chain.value = serverChain;
-				defaultTrustManager.checkServerTrusted(serverChain, authType);
-			}
-
-			@Override
-			public X509Certificate[] getAcceptedIssuers() {
-				throw new UnsupportedOperationException();
-			}
-		} }, null);
-		SSLSocketFactory factory = context.getSocketFactory();
-		try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
-			socket.setSoTimeout(timeout);
-			socket.startHandshake();
-		} catch (SSLException e) {
-			// Ignore
-		}
-		return chain.value;
-	}
-
-	private Map<URI, List<X509Certificate>> cache = new HashMap<>();
-
-	/**
-	 * Gets the certificate chain for a service identified by URI.
-	 * 
-	 * @param uri
-	 *            The URI of the (secure) service to identify.
-	 * @return The certificate chain. Will be <tt>null</tt> if the service is
-	 *         not secure.
-	 * @throws IOException
-	 *             If the service is unreachable or other connection problems
-	 *             occur.
-	 * @throws GeneralSecurityException
-	 *             If any of a number of security-related problems occur, such
-	 *             as an inability to match detailed security protocols.
-	 */
-	public List<X509Certificate> getTrustsForURI(URI uri) throws IOException,
-			GeneralSecurityException {
-		if (!secure)
-			return null;
-		synchronized (this) {
-			if (!cache.containsKey(uri)) {
-				int port = uri.getPort();
-				if (port == -1)
-					switch (uri.getScheme()) {
-					case "http":
-						port = 80;
-						break;
-					case "https":
-						port = 443;
-						break;
-					default:
-						return null;
-					}
-				X509Certificate[] chain = getCertificateChainForService(
-						uri.getHost(), port);
-				if (chain != null)
-					cache.put(uri, unmodifiableList(asList(chain)));
-				else
-					cache.put(uri, null);
-			}
-			return cache.get(uri);
-		}
-	}
-
-	/**
-	 * Flushes the cache.
-	 */
-	public void flushCache() {
-		synchronized (this) {
-			cache.clear();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java b/server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
deleted file mode 100644
index 884ff94..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import javax.servlet.ServletContext;
-import javax.ws.rs.core.UriInfo;
-
-import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.common.version.Version;
-
-/**
- * Convert a string (URL, etc) to a version that is contextualized to the
- * web-application.
- * 
- * @author Donal Fellows
- */
-public class Contextualizer implements ServletContextAware {
-	static final String ROOT_PLACEHOLDER = "%{WEBAPPROOT}";
-	static final String VERSION_PLACEHOLDER = "%{VERSION}";
-	static final String BASE_PLACEHOLDER = "%{BASEURL}";
-
-	/**
-	 * Apply the contextualization operation. This consists of replacing the
-	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the webapp.
-	 * 
-	 * @param input
-	 *            the string to contextualize
-	 * @return the contextualized string
-	 */
-	public String contextualize(String input) {
-		// Hack to work around bizarre CXF bug
-		String path = context.getRealPath("/").replace("%2D", "-");
-		return input.replace(ROOT_PLACEHOLDER, path).replace(
-				VERSION_PLACEHOLDER, Version.JAVA);
-	}
-
-	/**
-	 * Apply the contextualization operation. This consists of replacing the
-	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the
-	 * webapp.
-	 * 
-	 * @param ui
-	 *            Where to get information about the URL used to access the
-	 *            webapp.
-	 * @param input
-	 *            the string to contextualize
-	 * @return the contextualized string
-	 */
-	public String contextualize(UriInfo ui, String input) {
-		// Hack to work around bizarre CXF bug
-		String baseuri = ui.getBaseUri().toString().replace("%2D", "-");
-		if (baseuri.endsWith("/"))
-			baseuri = baseuri.substring(0, baseuri.length() - 1);
-		return contextualize(input).replace(BASE_PLACEHOLDER, baseuri);
-	}
-
-	private ServletContext context;
-
-	@Override
-	public void setServletContext(ServletContext servletContext) {
-		context = servletContext;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java b/server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
deleted file mode 100644
index f8b39e3..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.taverna.server.master.utils;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Utility class, used to make Derby less broken.
- * 
- * @see <a
- *      href="http://stackoverflow.com/questions/1004327/getting-rid-of-derby-log">
- *      Getting rid of derby.log </a>
- * @see <a
- *      href="http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file">
- *      Set system property with Spring configuration file </a>
- */
-public class DerbyUtils {
-	/**
-	 * A writer that channels things on to the log.
-	 */
-	public static final Writer TO_LOG = new DBLog();
-	// Hack
-	public static final Writer DEV_NULL = TO_LOG;
-}
-
-class DBLog extends Writer {
-	private Log log = LogFactory.getLog("Taverna.Server.Database");
-	private StringBuilder sb = new StringBuilder();
-	private boolean closed = false;
-
-	@Override
-	public void write(char[] cbuf, int off, int len) throws IOException {
-		if (closed)
-			throw new EOFException();
-		if (!log.isInfoEnabled())
-			return;
-		sb.append(cbuf, off, len);
-		while (!closed) {
-			int idx = sb.indexOf("\n"), realIdx = idx;
-			if (idx < 0)
-				break;
-			char ch;
-			while (idx > 0 && ((ch = sb.charAt(idx - 1)) == '\r' || ch == ' ' || ch == '\t'))
-				idx--;
-			if (idx > 0)
-				log.info(sb.substring(0, idx));
-			sb.delete(0, realIdx + 1);
-		}
-	}
-
-	@Override
-	public void flush() throws IOException {
-		if (sb.length() > 0) {
-			log.info(sb.toString());
-			sb = new StringBuilder();
-		}
-	}
-
-	@Override
-	public void close() throws IOException {
-		flush();
-		closed = true;
-		sb = null;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java b/server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
deleted file mode 100644
index 19299e2..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import java.util.List;
-
-import javax.ws.rs.core.PathSegment;
-
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-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.TavernaRun;
-
-/**
- * Utility functions for getting entries from directories.
- * 
- * @author Donal Fellows
- */
-public class FilenameUtils {
-	private static final String TYPE_ERROR = "trying to take subdirectory of file";
-	private static final String NO_FILE = "no such directory entry";
-	private static final String NOT_A_FILE = "not a file";
-	private static final String NOT_A_DIR = "not a directory";
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the directory entry to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path; an empty path will retrieve the working directory handle
-	 *         itself.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (name == null || name.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		// Must be nested loops; avoids problems with %-encoded "/" chars
-		for (String bit : name.split("/")) {
-			if (mustBeLast)
-				throw new FilesystemAccessException(TYPE_ERROR);
-			found = getEntryFromDir(bit, dir);
-			dir = null;
-			if (found instanceof Directory) {
-				dir = (Directory) found;
-				mustBeLast = false;
-			} else
-				mustBeLast = true;
-		}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The path segments describing what to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path; an empty path will retrieve the working directory handle
-	 *         itself.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, List<PathSegment> d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (d == null || d.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		// Must be nested loops; avoids problems with %-encoded "/" chars
-		for (PathSegment segment : d)
-			for (String bit : segment.getPath().split("/")) {
-				if (mustBeLast)
-					throw new FilesystemAccessException(TYPE_ERROR);
-				found = getEntryFromDir(bit, dir);
-				dir = null;
-				if (found instanceof Directory) {
-					dir = (Directory) found;
-					mustBeLast = false;
-				} else
-					mustBeLast = true;
-			}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The directory entry whose name is equal to the last part of the
-	 *         path in the directory reference; an empty path will retrieve the
-	 *         working directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public DirectoryEntry getDirEntry(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		Directory dir = run.getWorkingDirectory();
-		if (d == null || d.path == null || d.path.isEmpty())
-			return dir;
-		DirectoryEntry found = dir;
-		boolean mustBeLast = false;
-
-		for (String bit : d.path.split("/")) {
-			if (mustBeLast)
-				throw new FilesystemAccessException(TYPE_ERROR);
-			found = getEntryFromDir(bit, dir);
-			dir = null;
-			if (found instanceof Directory) {
-				dir = (Directory) found;
-				mustBeLast = false;
-			} else
-				mustBeLast = true;
-		}
-		return found;
-	}
-
-	/**
-	 * Get a named directory entry from a directory.
-	 * 
-	 * @param name
-	 *            The name of the entry; must be "<tt>/</tt>"-free.
-	 * @param dir
-	 *            The directory to look in.
-	 * @return The directory entry whose name is equal to the given name.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable.
-	 */
-	private DirectoryEntry getEntryFromDir(String name, Directory dir)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		if (dir == null)
-			throw new FilesystemAccessException(NO_FILE);
-		for (DirectoryEntry entry : dir.getContents())
-			if (entry.getName().equals(name))
-				return entry;
-		throw new NoDirectoryEntryException(NO_FILE);
-	}
-
-	/**
-	 * Get a named directory from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The directory whose name is equal to the last part of the path in
-	 *         the directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable, or if the
-	 *             name doesn't refer to a directory.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public Directory getDirectory(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, d);
-		if (dirEntry instanceof Directory)
-			return (Directory) dirEntry;
-		throw new FilesystemAccessException(NOT_A_DIR);
-	}
-
-	/**
-	 * Get a named directory from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the directory to look up.
-	 * @return The directory.
-	 * @throws FilesystemAccessException
-	 *             If the directory isn't specified or isn't readable, or if the
-	 *             name doesn't refer to a directory.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public Directory getDirectory(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, name);
-		if (dirEntry instanceof Directory)
-			return (Directory) dirEntry;
-		throw new FilesystemAccessException(NOT_A_DIR);
-	}
-
-	/**
-	 * Get a named file from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param d
-	 *            The directory reference describing what to look up.
-	 * @return The file whose name is equal to the last part of the path in the
-	 *         directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the file isn't specified or isn't readable, or if the name
-	 *             doesn't refer to a file.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public File getFile(TavernaRun run, DirEntryReference d)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, d);
-		if (dirEntry instanceof File)
-			return (File) dirEntry;
-		throw new FilesystemAccessException(NOT_A_FILE);
-	}
-
-	/**
-	 * Get a named file from a workflow run.
-	 * 
-	 * @param run
-	 *            The run whose working directory is to be used as the root of
-	 *            the search.
-	 * @param name
-	 *            The name of the file to look up.
-	 * @return The file whose name is equal to the last part of the path in the
-	 *         directory reference; an empty path will retrieve the working
-	 *         directory handle itself.
-	 * @throws FilesystemAccessException
-	 *             If the file isn't specified or isn't readable, or if the name
-	 *             doesn't refer to a file.
-	 * @throws NoDirectoryEntryException
-	 *             If there is no such entry.
-	 */
-	public File getFile(TavernaRun run, String name)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		DirectoryEntry dirEntry = getDirEntry(run, name);
-		if (dirEntry instanceof File)
-			return (File) dirEntry;
-		throw new FilesystemAccessException(NOT_A_FILE);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java b/server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
deleted file mode 100644
index ff52e81..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.taverna.server.master.utils;
-
-import org.apache.cxf.jaxrs.provider.ProviderFactory;
-import org.apache.cxf.message.Message;
-import org.apache.cxf.phase.AbstractPhaseInterceptor;
-import org.apache.cxf.phase.Phase;
-
-public class FlushThreadLocalCacheInterceptor extends
-		AbstractPhaseInterceptor<Message> {
-	public FlushThreadLocalCacheInterceptor() {
-		super(Phase.USER_LOGICAL_ENDING);
-	}
-
-	@Override
-	public void handleMessage(Message message) {
-		ProviderFactory.getInstance(message).clearThreadLocalProxies();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java b/server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
deleted file mode 100644
index 55a260b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-
-/**
- * This class is responsible for counting all invocations of publicly-exposed
- * methods of the webapp. It's connected to the webapp primarily through an
- * AspectJ-style pointcut.
- * 
- * @author Donal Fellows
- */
-@Aspect
-public class InvocationCounter {
-	private int count;
-
-	@Before("@annotation(org.taverna.server.master.utils.InvocationCounter.CallCounted)")
-	public synchronized void count() {
-		count++;
-	}
-
-	public synchronized int getCount() {
-		return count;
-	}
-
-	/**
-	 * Mark methods that should be counted by the invocation counter.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Retention(RUNTIME)
-	@Documented
-	@Target(METHOD)
-	public static @interface CallCounted {
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java b/server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
deleted file mode 100644
index 252e316..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.Integer.MAX_VALUE;
-import static javax.crypto.Cipher.getMaxAllowedKeyLength;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.security.GeneralSecurityException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.annotation.PostConstruct;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Trivial bean that checks for whether the JCE policy files that allow
- * unlimited strength security are present, and warns in the log if not.
- * 
- * @author Donal Fellows
- */
-public class JCECheck {
-	/**
-	 * Write a message to the log that says whether an unlimited strength
-	 * {@linkplain #Cipher cipher} is present. This is the official proxy for
-	 * whether the unlimited strength JCE policy files have been installed; if
-	 * absent, the message is logged as a warning, otherwise it is just
-	 * informational.
-	 */
-	@PostConstruct
-	public void checkForUnlimitedJCE() {
-		Log log = getLog("Taverna.Server.Utils");
-
-		try {
-			if (getMaxAllowedKeyLength("AES") < MAX_VALUE)
-				log.warn("maximum key length very short; unlimited "
-						+ "strength JCE policy files maybe missing");
-			else
-				log.info("unlimited strength JCE policy in place");
-		} catch (GeneralSecurityException e) {
-			log.warn("problem computing key length limits!", e);
-		}
-	}
-
-	/**
-	 * @return Whether the unlimited strength JCE policy files are present (or
-	 *         rather whether an unlimited strength {@linkplain #Cipher cipher}
-	 *         is permitted).
-	 */
-	public boolean isUnlimitedStrength() {
-		try {
-			return getMaxAllowedKeyLength("AES") == MAX_VALUE;
-		} catch (NoSuchAlgorithmException e) {
-			return false;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java b/server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
deleted file mode 100644
index ba9ec81..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import java.util.WeakHashMap;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-import javax.jdo.JDOException;
-import javax.jdo.PersistenceManager;
-import javax.jdo.PersistenceManagerFactory;
-import javax.jdo.Query;
-import javax.jdo.Transaction;
-
-import org.apache.commons.logging.Log;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Simple support class that wraps up and provides access to the correct parts
- * of JDO.
- * 
- * @author Donal Fellows
- * 
- * @param &lt;T&gt; The context class that the subclass will be working with.
- */
-public abstract class JDOSupport<T> {
-	private Class<T> contextClass;
-	private PersistenceManagerBuilder pmb;
-
-	/**
-	 * Instantiate this class, supplying it a handle to the class that will be
-	 * used to provide context for queries and accesses.
-	 * 
-	 * @param contextClass
-	 *            Must match the type parameter to the class itself.
-	 */
-	protected JDOSupport(@Nonnull Class<T> contextClass) {
-		this.contextClass = contextClass;
-	}
-
-	/**
-	 * @param persistenceManagerBuilder
-	 *            The JDO engine to use for managing persistence.
-	 */
-	@Required
-	public void setPersistenceManagerBuilder(
-			PersistenceManagerBuilder persistenceManagerBuilder) {
-		pmb = persistenceManagerBuilder;
-	}
-
-	private PersistenceManager pm() {
-		if (isPersistent())
-			return pmb.getPersistenceManager();
-		return null;
-	}
-
-	/**
-	 * Has this class actually been configured with a persistence manager by
-	 * Spring?
-	 * 
-	 * @return Whether there is a persistence manager installed.
-	 */
-	protected boolean isPersistent() {
-		return pmb != null;
-	}
-
-	/**
-	 * Get an instance of a query in JDOQL.
-	 * 
-	 * @param filter
-	 *            The filter part of the query.
-	 * @return The query, which should be executed to retrieve the results.
-	 */
-	@Nonnull
-	protected Query query(@Nonnull String filter) {
-		return pm().newQuery(contextClass, filter);
-	}
-
-	/**
-	 * Get an instance of a named query attached to the context class (as an
-	 * annotation).
-	 * 
-	 * @param name
-	 *            The name of the query.
-	 * @return The query, which should be executed to retrieve the results.
-	 * @see javax.jdo.annotations.Query
-	 */
-	@Nonnull
-	protected Query namedQuery(@Nonnull String name) {
-		return pm().newNamedQuery(contextClass, name);
-	}
-
-	/**
-	 * Make an instance of the context class persist in the database. It's
-	 * identity must not already exist.
-	 * 
-	 * @param value
-	 *            The instance to persist.
-	 * @return The persistence-coupled instance.
-	 */
-	@Nullable
-	protected T persist(@Nullable T value) {
-		if (value == null)
-			return null;
-		return pm().makePersistent(value);
-	}
-
-	/**
-	 * Make a non-persistent (i.e., will hold its value past the end of the
-	 * transaction) copy of a persistence-coupled instance of the context class.
-	 * 
-	 * @param value
-	 *            The value to decouple.
-	 * @return The non-persistent copy.
-	 */
-	@Nullable
-	protected T detach(@Nullable T value) {
-		if (value == null)
-			return null;
-		return pm().detachCopy(value);
-	}
-
-	/**
-	 * Look up an instance of the context class by its identity.
-	 * 
-	 * @param id
-	 *            The identity of the object.
-	 * @return The instance, which is persistence-coupled.
-	 */
-	@Nullable
-	protected T getById(Object id) {
-		try {
-			return pm().getObjectById(contextClass, id);
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Delete a persistence-coupled instance of the context class.
-	 * 
-	 * @param value
-	 *            The value to delete.
-	 */
-	protected void delete(@Nullable T value) {
-		if (value != null)
-			pm().deletePersistent(value);
-	}
-
-	/**
-	 * Manages integration of JDO transactions with Spring.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Aspect
-	public static class TransactionAspect {
-		private Object lock = new Object();
-		private Log log = getLog("Taverna.Server.Utils");
-		private volatile int txid;
-
-		@Around(value = "@annotation(org.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
-		Object applyTransaction(ProceedingJoinPoint pjp, JDOSupport<?> support)
-				throws Throwable {
-			synchronized (lock) {
-				PersistenceManager pm = support.pm();
-				int id = ++txid;
-				Transaction tx = (pm == null) ? null : pm.currentTransaction();
-				if (tx != null && tx.isActive())
-					tx = null;
-				if (tx != null) {
-					if (log.isDebugEnabled())
-						log.debug("starting transaction #" + id);
-					tx.begin();
-				}
-				try {
-					Object result = pjp.proceed();
-					if (tx != null) {
-						tx.commit();
-						if (log.isDebugEnabled())
-							log.debug("committed transaction #" + id);
-					}
-					tx = null;
-					return result;
-				} catch (Throwable t) {
-					try {
-						if (tx != null) {
-							tx.rollback();
-							if (log.isDebugEnabled())
-								log.debug("rolled back transaction #" + id);
-						}
-					} catch (JDOException e) {
-						log.warn("rollback failed unexpectedly", e);
-					}
-					throw t;
-				}
-			}
-		}
-	}
-
-	/**
-	 * Mark a method (of a subclass of {@link JDOSupport}) as having a
-	 * transaction wrapped around it. The transactions are managed correctly in
-	 * the multi-threaded case.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Target(METHOD)
-	@Retention(RUNTIME)
-	@Documented
-	public @interface WithinSingleTransaction {
-	}
-
-	/**
-	 * Manages {@linkplain PersistenceManager persistence managers} in a way
-	 * that doesn't cause problems when the web application is unloaded.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public static class PersistenceManagerBuilder {
-		private PersistenceManagerFactory pmf;
-		private WeakHashMap<Thread, PersistenceManager> cache = new WeakHashMap<>();
-
-		/**
-		 * @param persistenceManagerFactory
-		 *            The JDO engine to use for managing persistence.
-		 */
-		@Required
-		public void setPersistenceManagerFactory(
-				PersistenceManagerFactory persistenceManagerFactory) {
-			pmf = persistenceManagerFactory;
-		}
-
-		@Nonnull
-		public PersistenceManager getPersistenceManager() {
-			if (cache == null)
-				return pmf.getPersistenceManager();
-			Thread t = Thread.currentThread();
-			PersistenceManager pm = cache.get(t);
-			if (pm == null && pmf != null) {
-				pm = pmf.getPersistenceManager();
-				cache.put(t, pm);
-			}
-			return pm;
-		}
-
-		@PreDestroy
-		void clearThreadCache() {
-			WeakHashMap<Thread, PersistenceManager> cache = this.cache;
-			this.cache = null;
-			for (PersistenceManager pm : cache.values())
-				if (pm != null)
-					pm.close();
-			cache.clear();
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java b/server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
deleted file mode 100644
index a8aa937..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package org.taverna.server.master.utils;
-
-import static java.lang.System.currentTimeMillis;
-import static java.lang.Thread.sleep;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.sql.DatabaseMetaData;
-import java.util.Properties;
-
-import org.apache.commons.logging.Log;
-import org.datanucleus.store.rdbms.adapter.DerbyAdapter;
-import org.datanucleus.store.rdbms.identifier.IdentifierFactory;
-import org.datanucleus.store.rdbms.key.CandidateKey;
-import org.datanucleus.store.rdbms.key.ForeignKey;
-import org.datanucleus.store.rdbms.key.Index;
-import org.datanucleus.store.rdbms.key.PrimaryKey;
-import org.datanucleus.store.rdbms.sql.SQLTable;
-import org.datanucleus.store.rdbms.table.Column;
-import org.datanucleus.store.rdbms.table.Table;
-import org.datanucleus.store.rdbms.table.TableImpl;
-import org.datanucleus.store.rdbms.table.ViewImpl;
-
-/**
- * Evil hack to allow logging of the DDL spat out to Derby.
- * 
- * @author Donal Fellows
- */
-public class LoggingDerbyAdapter extends DerbyAdapter {
-	Log log = getLog("Taverna.Server.SQL");
-
-	private StringBuilder ddl = new StringBuilder();
-	private volatile long timeout;
-	private Thread timer;
-
-	private synchronized void logDDL() {
-		if (ddl.length() > 0) {
-			log.info("Data definition language:\n" + ddl);
-			ddl.setLength(0);
-		}
-		timer = null;
-	}
-
-	private synchronized void doLog(String item) {
-		ddl.append(item);
-		if (!item.endsWith("\n"))
-			ddl.append('\n');
-		timeout = currentTimeMillis() + 5000;
-		if (timer == null)
-			timer = new OneShotThread("DDL logger timeout", new Runnable() {
-				@Override
-				public void run() {
-					try {
-						while (timeout > currentTimeMillis())
-							sleep(1000);
-					} catch (InterruptedException e) {
-						// Ignore
-					}
-					logDDL();
-				}
-			});
-	}
-
-	/**
-	 * Creates an Apache Derby adapter based on the given metadata which logs
-	 * the DDL it creates.
-	 */
-	public LoggingDerbyAdapter(DatabaseMetaData metadata) {
-		super(metadata);
-	}
-
-	@Override
-	public String getCreateTableStatement(TableImpl table, Column[] columns,
-			Properties props, IdentifierFactory factory) {
-		String statement = super.getCreateTableStatement(table, columns, props,
-				factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getCreateIndexStatement(Index index, IdentifierFactory factory) {
-		String statement = super.getCreateIndexStatement(index, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddCandidateKeyStatement(CandidateKey ck,
-			IdentifierFactory factory) {
-		String statement = super.getAddCandidateKeyStatement(ck, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddPrimaryKeyStatement(PrimaryKey pk,
-			IdentifierFactory factory) {
-		String statement = super.getAddPrimaryKeyStatement(pk, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddColumnStatement(Table table, Column col) {
-		String statement = super.getAddColumnStatement(table, col);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getAddForeignKeyStatement(ForeignKey fk,
-			IdentifierFactory factory) {
-		String statement = super.getAddForeignKeyStatement(fk, factory);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDeleteTableStatement(SQLTable tbl) {
-		String statement = super.getDeleteTableStatement(tbl);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDropTableStatement(Table table) {
-		String statement = super.getDropTableStatement(table);
-		doLog(statement);
-		return statement;
-	}
-
-	@Override
-	public String getDropViewStatement(ViewImpl view) {
-		String statement = super.getDropViewStatement(view);
-		doLog(statement);
-		return statement;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java b/server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
deleted file mode 100644
index 68b813d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.taverna.server.master.utils;
-
-public class OneShotThread extends Thread {
-	public OneShotThread(String name, Runnable target) {
-		super(target, name);
-		setContextClassLoader(null);
-		setDaemon(true);
-		start();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java b/server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
deleted file mode 100644
index a892b52..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.core.Response;
-
-/**
- * Utilities that make it easier to write REST services.
- * 
- * @author Donal Fellows
- */
-public class RestUtils {
-	/**
-	 * Generate a response to an HTTP OPTIONS request.
-	 * 
-	 * @param methods
-	 *            The state-changing methods supported, if any.
-	 * @return the required response
-	 * @see OPTIONS
-	 */
-	public static Response opt(String... methods) {
-		StringBuilder sb = new StringBuilder("GET,");
-		for (String m : methods)
-			sb.append(m).append(",");
-		sb.append("HEAD,OPTIONS");
-		return Response.ok().header("Allow", sb.toString()).entity("").build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java b/server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
deleted file mode 100644
index 0b2d4ea..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.taverna.server.master.exceptions.GeneralFailureException;
-
-/**
- * Aspect used to convert {@linkplain RuntimeException runtime exceptions} into
- * a form that can be nicely conveyed to the outside world as HTTP errors.
- * 
- * @author Donal Fellows
- */
-@Aspect
-public class RuntimeExceptionWrapper {
-	/**
-	 * Map an unexpected exception to one that can be correctly reported as a
-	 * problem.
-	 * 
-	 * @param exn
-	 *            The runtime exception being trapped.
-	 * @throws GeneralFailureException
-	 *             The known exception type that it is mapped to.
-	 */
-	@AfterThrowing(pointcut = "execution(* org.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
-	public void wrapRuntimeException(RuntimeException exn)
-			throws GeneralFailureException {
-		// Exclude security-related exceptions
-		if (exn.getClass().getName().startsWith("org.springframework.security."))
-			return;
-		throw new GeneralFailureException(exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java b/server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
deleted file mode 100644
index 9bbcc2f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import java.io.Serializable;
-import java.security.Principal;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.userdetails.UserDetails;
-
-/**
- * A simple serializable principal that just records the name.
- * 
- * @author Donal Fellows
- */
-public class UsernamePrincipal implements Principal, Serializable {
-	private static final long serialVersionUID = 2703493248562435L;
-	public UsernamePrincipal(String username) {
-		this.name = username;
-	}
-
-	public UsernamePrincipal(Principal other) {
-		this.name = other.getName();
-	}
-
-	public UsernamePrincipal(Authentication auth) {
-		this(auth.getPrincipal());
-	}
-
-	public UsernamePrincipal(Object principal) {
-		if (principal instanceof Principal)
-			this.name = ((Principal) principal).getName();
-		else if (principal instanceof String)
-			this.name = (String) principal;
-		else if (principal instanceof UserDetails)
-			this.name = ((UserDetails) principal).getUsername();
-		else
-			this.name = principal.toString();
-	}
-
-	private String name;
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public String toString() {
-		return "Principal<" + name + ">";
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (o instanceof Principal) {
-			Principal p = (Principal) o;
-			return name.equals(p.getName());
-		}
-		return false;
-	}
-
-	@Override
-	public int hashCode() {
-		return name.hashCode();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java b/server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
deleted file mode 100644
index 96cdc6d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.taverna.server.master.utils;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.apache.cxf.common.util.UrlUtils.parseQueryString;
-import static org.apache.cxf.message.Message.HTTP_REQUEST_METHOD;
-import static org.apache.cxf.message.Message.QUERY_STRING;
-import static org.apache.cxf.message.Message.REQUEST_URL;
-import static org.apache.cxf.phase.Phase.READ;
-
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.cxf.binding.soap.interceptor.EndpointSelectionInterceptor;
-import org.apache.cxf.interceptor.Fault;
-import org.apache.cxf.message.Message;
-import org.apache.cxf.phase.AbstractPhaseInterceptor;
-
-
-/**
- * Thunk for TAVSERV-293.
- * 
- * @author Donal Fellows (based on work by Daniel Hagen)
- */
-public class WSDLHeadOptionsInterceptor extends
-		AbstractPhaseInterceptor<Message> {
-	public static final Log log = getLog("Taverna.Server.Utils");
-
-	public WSDLHeadOptionsInterceptor() {
-		super(READ);
-		getAfter().add(EndpointSelectionInterceptor.class.getName());
-	}
-
-	@Override
-	public void handleMessage(Message message) throws Fault {
-		String method = (String) message.get(HTTP_REQUEST_METHOD);
-		String query = (String) message.get(QUERY_STRING);
-
-		if (("HEAD".equals(method) || "OPTIONS".equals(method))
-				&& query != null && !query.trim().isEmpty()
-				&& isRecognizedQuery(query)) {
-			log.debug("adjusting message request method " + method + " for "
-					+ message.get(REQUEST_URL) + " to GET");
-			message.put(HTTP_REQUEST_METHOD, "GET");
-		}
-	}
-
-	/*
-	 * Stolen from http://permalink.gmane.org/gmane.comp.apache.cxf.user/20037
-	 * which is itself in turn stolen from
-	 * org.apache.cxf.frontend.WSDLGetInterceptor.isRecognizedQuery
-	 */
-	/**
-	 * Is this a query for WSDL or XSD relating to it?
-	 * 
-	 * @param query
-	 *            The query string to check
-	 * @return If the query is one to handle.
-	 * @see org.apache.cxf.frontend.WSDLGetInterceptor#isRecognizedQuery(Map,String,String,org.apache.cxf.service.model.EndpointInfo)
-	 *      WSDLGetInterceptor
-	 */
-	private boolean isRecognizedQuery(String query) {
-		Map<String, String> map = parseQueryString(query);
-		return map.containsKey("wsdl") || map.containsKey("xsd");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java b/server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
deleted file mode 100644
index 03fc749..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.Thread.currentThread;
-import static java.sql.DriverManager.deregisterDriver;
-import static java.sql.DriverManager.getDrivers;
-import static org.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Enumeration;
-
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Add some awareness of the context so that we can locate databases internally
- * to the webapp.
- * 
- * @author Donal Fellows
- */
-public class WebappAwareDataSource extends BasicDataSource {
-	Log log = LogFactory.getLog("Taverna.Server.Utils");
-	private transient boolean init;
-	private Contextualizer ctxt;
-	private String shutdownUrl;
-
-	@Required
-	public void setContextualizer(Contextualizer ctxt) {
-		this.ctxt = ctxt;
-	}
-
-	/**
-	 * A JDBC connection URL to use on shutting down the database. If not set,
-	 * do nothing special.
-	 * 
-	 * @param url
-	 */
-	public void setShutdownUrl(String url) {
-		shutdownUrl = url;
-	}
-
-	private void doInit() {
-		synchronized (this) {
-			if (!init) {
-				setDriverClassLoader(currentThread().getContextClassLoader());
-				String url = getUrl();
-				if (url.contains(ROOT_PLACEHOLDER)) {
-					String newurl = ctxt.contextualize(url);
-					setUrl(newurl);
-					log.info("mapped " + url + " to " + newurl);
-				} else {
-					log.info("did not find " + ROOT_PLACEHOLDER + " in " + url);
-				}
-				init = true;
-			}
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=- HOOKS -=-=-=-=-=-=-=-=-=-=-
-
-	@Override
-	public Connection getConnection() throws SQLException {
-		doInit();
-		return super.getConnection();
-	}
-
-	@Override
-	public void setLogWriter(PrintWriter pw) throws SQLException {
-		doInit();
-		super.setLogWriter(pw);
-	}
-
-	@Override
-	public void setLoginTimeout(int num) throws SQLException {
-		doInit();
-		super.setLoginTimeout(num);
-	}
-
-	@Override
-	public PrintWriter getLogWriter() throws SQLException {
-		doInit();
-		return super.getLogWriter();
-	}
-
-	@Override
-	public int getLoginTimeout() throws SQLException {
-		doInit();
-		return super.getLoginTimeout();
-	}
-
-	@PreDestroy
-	void realClose() {
-		try {
-			close();
-		} catch (SQLException e) {
-			log.warn("problem shutting down DB connection", e);
-		}
-		try {
-			if (shutdownUrl != null)
-				DriverManager.getConnection(ctxt.contextualize(shutdownUrl));
-		} catch (SQLException e) {
-			// Expected; ignore it
-		}
-		log = null;
-		dropDriver();
-	}
-
-	private void dropDriver() {
-		Enumeration<Driver> drivers = getDrivers();
-		while (drivers.hasMoreElements()) {
-			Driver d = drivers.nextElement();
-			if (d.getClass().getClassLoader() == getDriverClassLoader()
-					&& d.getClass().getName().equals(getDriverClassName())) {
-				try {
-					deregisterDriver(d);
-				} catch (SQLException e) {
-				}
-				break;
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java b/server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
deleted file mode 100644
index da4cff0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static javax.security.auth.x500.X500Principal.RFC2253;
-
-import java.math.BigInteger;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.PreDestroy;
-import javax.security.auth.x500.X500Principal;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Support class that factors out some of the messier parts of working with
- * X.500 identities and X.509 certificates.
- * 
- * @author Donal Fellows
- */
-public class X500Utils {
-	private Log log = LogFactory.getLog("Taverna.Server.Utils");
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	private static final char DN_SEPARATOR = ',';
-	private static final char DN_ESCAPE = '\\';
-	private static final char DN_QUOTE = '"';
-
-	/**
-	 * Parse the DN from the Principal and extract the CN field.
-	 * 
-	 * @param id
-	 *            The identity to extract the distinguished name from.
-	 * @param fields
-	 *            The names to look at when finding the field to return. Each
-	 *            should be an upper-cased string.
-	 * @return The common-name part of the distinguished name, or the literal
-	 *         string "<tt>none</tt>" if there is no CN.
-	 */
-	public String getName(X500Principal id, String... fields) {
-		String dn = id.getName(RFC2253);
-
-		int i = 0;
-		int startIndex = 0;
-		boolean ignoreThisChar = false;
-		boolean inQuotes = false;
-		Map<String, String> tokenized = new HashMap<>();
-
-		for (i = 0; i < dn.length(); i++)
-			if (ignoreThisChar)
-				ignoreThisChar = false;
-			else if (dn.charAt(i) == DN_QUOTE)
-				inQuotes = !inQuotes;
-			else if (inQuotes)
-				continue;
-			else if (dn.charAt(i) == DN_ESCAPE)
-				ignoreThisChar = true;
-			else if ((dn.charAt(i) == DN_SEPARATOR) && !ignoreThisChar) {
-				storeDNField(tokenized, dn.substring(startIndex, i).trim()
-						.split("=", 2));
-				startIndex = i + 1;
-			}
-		if (inQuotes || ignoreThisChar)
-			log.warn("was parsing invalid DN format");
-		// Add last token - after the last delimiter
-		storeDNField(tokenized, dn.substring(startIndex).trim().split("=", 2));
-
-		for (String field : fields) {
-			String value = tokenized.get(field);
-			if (value != null)
-				return value;
-		}
-		return "none";
-	}
-
-	private void storeDNField(Map<String, String> container, String[] split) {
-		if (split == null || split.length != 2)
-			return;
-		String key = split[0].toUpperCase();
-		if (container.containsKey(key))
-			log.warn("duplicate field in DN: " + key);
-		// LATER: Should the field be de-quoted?
-		container.put(key, split[1]);
-	}
-
-	/**
-	 * Get the serial number from a certificate as a hex string.
-	 * 
-	 * @param cert
-	 *            The certificate to extract from.
-	 * @return A hex string, in upper-case.
-	 */
-	public String getSerial(X509Certificate cert) {
-		return new BigInteger(1, cert.getSerialNumber().toByteArray())
-				.toString(16).toUpperCase();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
deleted file mode 100644
index 612e61c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Miscellaneous utility classes. Includes aspects that might be attached
- * for purposes such as transaction management and invocation tracking.
- */
-package org.taverna.server.master.utils;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java b/server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
deleted file mode 100644
index 10b3830..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-
-/**
- * How to convert a notification about the completion of a job into a message.
- * 
- * @author Donal Fellows
- */
-public interface CompletionNotifier {
-	/**
-	 * @return The name of this notifier.
-	 */
-	String getName();
-
-	/**
-	 * Called to get the content of a message that a workflow run has finished.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param run
-	 *            What run are we talking about.
-	 * @param code
-	 *            What the exit code was.
-	 * @return The plain-text content of the message.
-	 */
-	String makeCompletionMessage(String name, RemoteRunDelegate run, int code);
-
-	/**
-	 * Called to get the subject of the message to dispatch.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param run
-	 *            What run are we talking about.
-	 * @param code
-	 *            What the exit code was.
-	 * @return The plain-text subject of the message.
-	 */
-	String makeMessageSubject(String name, RemoteRunDelegate run, int code);
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java b/server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
deleted file mode 100644
index 5d0f371..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import org.taverna.server.master.notification.atom.EventDAO;
-
-/**
- * What the remote run really needs of its factory.
- * 
- * @author Donal Fellows
- */
-public interface FactoryBean {
-	/**
-	 * @return Whether a run can actually be started at this time.
-	 */
-	boolean isAllowingRunsToStart();
-
-	/**
-	 * @return a handle to the master Atom event feed (<i>not</i> the per-run
-	 *         feed)
-	 */
-	EventDAO getMasterEventFeed();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java b/server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
deleted file mode 100644
index d3c5b8a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.taverna.server.master.worker;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * A simple password issuing bean.
- * 
- * @author Donal Fellows
- */
-public class PasswordIssuer {
-	private static final char[] ALPHABET = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
-			'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
-			'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
-			'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7',
-			'8', '9', '0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
-			',', '.', '<', '>', '/', '?', ':', ';', '-', '_', '+', '[', ']',
-			'{', '}', '`', '~' };
-	private Log log = LogFactory.getLog("Taverna.Server.Worker");
-	private SecureRandom r;
-	private int length;
-
-	public PasswordIssuer() {
-		r = new SecureRandom();
-		log.info("constructing passwords with " + r.getAlgorithm());
-		setLength(8);
-	}
-
-	public PasswordIssuer(String algorithm) throws NoSuchAlgorithmException {
-		r = SecureRandom.getInstance(algorithm);
-		log.info("constructing passwords with " + r.getAlgorithm());
-		setLength(8);
-	}
-
-	public void setLength(int length) {
-		this.length = length;
-		log.info("issued password will be " + this.length
-				+ " symbols chosen from " + ALPHABET.length);
-	}
-
-	/**
-	 * Issue a password.
-	 * 
-	 * @return The new password.
-	 */
-	public String issue() {
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < length; i++)
-			sb.append(ALPHABET[r.nextInt(ALPHABET.length)]);
-		log.info("issued new password of length " + sb.length());
-		return sb.toString();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java b/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
deleted file mode 100644
index f5613c7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
-
-import java.net.URI;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.taverna.server.master.common.Roles;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Basic policy implementation that allows any workflow to be instantiated by
- * any user, but which does not permit users to access each others workflow
- * runs. It also imposes a global limit on the number of workflow runs at once.
- * 
- * @author Donal Fellows
- */
-class PolicyImpl implements Policy {
-	Log log = LogFactory.getLog("Taverna.Server.Worker.Policy");
-	private PolicyLimits limits;
-	private RunDBSupport runDB;
-
-	@Required
-	public void setLimits(PolicyLimits limits) {
-		this.limits = limits;
-	}
-
-	@Required
-	public void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return limits.getMaxRuns();
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal user) {
-		return null;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return limits.getOperatingLimit();
-	}
-
-	@Override
-	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
-		return limits.getPermittedWorkflowURIs();
-	}
-
-	private boolean isSelfAccess(String runId) {
-		Authentication auth = SecurityContextHolder.getContext()
-				.getAuthentication();
-		boolean self = false;
-		String id = null;
-		for (GrantedAuthority a : auth.getAuthorities()) {
-			String aa = a.getAuthority();
-			if (aa.equals(Roles.SELF)) {
-				self = true;
-				continue;
-			}
-			if (!aa.startsWith(PREFIX))
-				continue;
-			id = aa.substring(PREFIX.length());
-		}
-		return self && runId.equals(id);
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
-		String username = user.getName();
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner().getName().equals(username)) {
-			if (log.isDebugEnabled())
-				log.debug("granted access by " + user.getName() + " to "
-						+ run.getId());
-			return true;
-		}
-		if (isSelfAccess(run.getId())) {
-			if (log.isDebugEnabled())
-				log.debug("access by workflow to itself: " + run.getId());
-			return true;
-		}
-		if (log.isDebugEnabled())
-			log.debug("considering access by " + user.getName() + " to "
-					+ run.getId());
-		return context.getPermittedReaders().contains(username);
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException {
-		if (user == null)
-			throw new NoCreateException(
-					"anonymous workflow creation not allowed");
-		if (runDB.countRuns() >= getMaxRuns())
-			throw new NoCreateException("server load exceeded; please wait");
-	}
-
-	@Override
-	public synchronized void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException {
-		if (user == null)
-			throw new NoDestroyException();
-		String username = user.getName();
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner() == null
-				|| context.getOwner().getName().equals(username))
-			return;
-		if (!context.getPermittedDestroyers().contains(username))
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException {
-		if (user == null)
-			throw new NoUpdateException(
-					"workflow run not owned by you and you're not granted access");
-		TavernaSecurityContext context = run.getSecurityContext();
-		if (context.getOwner().getName().equals(user.getName()))
-			return;
-		if (isSelfAccess(run.getId())) {
-			if (log.isDebugEnabled())
-				log.debug("update access by workflow to itself: " + run.getId());
-			return;
-		}
-		if (!context.getPermittedUpdaters().contains(user.getName()))
-			throw new NoUpdateException(
-					"workflow run not owned by you and you're not granted access");
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(UsernamePrincipal user,
-			List<URI> permitted) {
-		limits.setPermittedWorkflowURIs(permitted);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java b/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
deleted file mode 100644
index 8cbc7ea..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-
-/**
- * The worker policy delegates certain limits to the state model of the
- * particular worker.
- * 
- * @author Donal Fellows
- */
-public interface PolicyLimits {
-	/**
-	 * @return the maximum number of extant workflow runs in any state
-	 */
-	int getMaxRuns();
-
-	/**
-	 * @return the maximum number of workflow runs in the
-	 *         {@linkplain Status#Operating operating} state.
-	 */
-	int getOperatingLimit();
-
-	/**
-	 * @return the list of URIs to workflows that may be used to create workflow
-	 *         runs. If empty or <tt>null</tt>, no restriction is present.
-	 */
-	List<URI> getPermittedWorkflowURIs();
-
-	/**
-	 * @param permitted
-	 *            the list of URIs to workflows that may be used to create
-	 *            workflow runs.
-	 */
-	void setPermittedWorkflowURIs(List<URI> permitted);
-}


[43/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
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;
-	}
-}


[39/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
deleted file mode 100644
index b227bfa..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/TavernaSecurityContext.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.util.Set;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.xml.ws.handler.MessageContext;
-
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Security context for a workflow run.
- * 
- * @author Donal Fellows
- */
-public interface TavernaSecurityContext {
-	/**
-	 * @return Who owns the security context.
-	 */
-	UsernamePrincipal getOwner();
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may destroy the run or manipulate its
-	 * lifetime.
-	 * 
-	 * @return The names of the users who may use destroy operations. Read-only.
-	 */
-	Set<String> getPermittedDestroyers();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may destroy the run or manipulate its
-	 * lifetime.
-	 * 
-	 * @param destroyers
-	 *            The names of the users who may use destroy operations.
-	 */
-	void setPermittedDestroyers(Set<String> destroyers);
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may update the run (including writing to
-	 * files).
-	 * 
-	 * @return The names of the users who may use update operations. Read-only.
-	 */
-	Set<String> getPermittedUpdaters();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may update the run (including writing to
-	 * its files).
-	 * 
-	 * @param updaters
-	 *            The names of the users who may use update operations.
-	 */
-	void setPermittedUpdaters(Set<String> updaters);
-
-	/**
-	 * Describe the names of the users (as extracted from their
-	 * {@link Principal} objects) that may read from the run (including its
-	 * files).
-	 * 
-	 * @return The names of the users who may use read operations. Read-only.
-	 */
-	Set<String> getPermittedReaders();
-
-	/**
-	 * Sets the collection of names of users (as extracted from their
-	 * {@link Principal} objects) that may read from the run (including its
-	 * files).
-	 * 
-	 * @param readers
-	 *            The names of the users who may use read operations.
-	 */
-	void setPermittedReaders(Set<String> readers);
-
-	/**
-	 * @return The credentials owned by the user. Never <tt>null</tt>.
-	 */
-	Credential[] getCredentials();
-
-	/**
-	 * Add a credential to the owned set or replaces the old version with the
-	 * new one.
-	 * 
-	 * @param toAdd
-	 *            The credential to add.
-	 */
-	void addCredential(Credential toAdd);
-
-	/**
-	 * Remove a credential from the owned set. It's not a failure to remove
-	 * something that isn't in the set.
-	 * 
-	 * @param toDelete
-	 *            The credential to remove.
-	 */
-	void deleteCredential(Credential toDelete);
-
-	/**
-	 * Tests if the credential is valid. This includes testing whether the
-	 * underlying credential file exists and can be unlocked by the password in
-	 * the {@link Credential} object.
-	 * 
-	 * @param c
-	 *            The credential object to validate.
-	 * @throws InvalidCredentialException
-	 *             If it is invalid.
-	 */
-	void validateCredential(Credential c) throws InvalidCredentialException;
-
-	/**
-	 * @return The identities trusted by the user. Never <tt>null</tt>.
-	 */
-	Trust[] getTrusted();
-
-	/**
-	 * Add an identity to the trusted set.
-	 * 
-	 * @param toAdd
-	 *            The identity to add.
-	 */
-	void addTrusted(Trust toAdd);
-
-	/**
-	 * Remove an identity from the trusted set. It's not a failure to remove
-	 * something that isn't in the set.
-	 * 
-	 * @param toDelete
-	 *            The identity to remove.
-	 */
-	void deleteTrusted(Trust toDelete);
-
-	/**
-	 * Tests if the trusted identity descriptor is valid. This includes checking
-	 * whether the underlying trusted identity file exists.
-	 * 
-	 * @param t
-	 *            The trusted identity descriptor to check.
-	 * @throws InvalidCredentialException
-	 *             If it is invalid.
-	 */
-	void validateTrusted(Trust t) throws InvalidCredentialException;
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param securityContext
-	 *            The security context associated with the request that caused
-	 *            the workflow to be created.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception;
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param context
-	 *            The full information about the request that caused the
-	 *            workflow to be created.
-	 */
-	void initializeSecurityFromSOAPContext(MessageContext context);
-
-	/**
-	 * Establish the security context from how the owning workflow run was
-	 * created. In particular, this gives an opportunity for boot-strapping
-	 * things with any delegateable credentials.
-	 * 
-	 * @param headers
-	 *            The full information about the request that caused the
-	 *            workflow to be created.
-	 */
-	void initializeSecurityFromRESTContext(HttpHeaders headers);
-
-	/**
-	 * Transfer the security context to the remote system.
-	 * 
-	 * @throws IOException
-	 *             If the communication fails.
-	 * @throws GeneralSecurityException
-	 *             If the assembly of the context fails.
-	 * @throws ImplementationException
-	 *             If the local worker has problems with creating the realized
-	 *             security context.
-	 */
-	void conveySecurity() throws GeneralSecurityException, IOException,
-			ImplementationException;
-
-	/**
-	 * @return The factory that created this security context.
-	 */
-	SecurityContextFactory getFactory();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
deleted file mode 100644
index e5cd02c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/UriBuilderFactory.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.interfaces;
-
-import java.net.URI;
-
-import javax.ws.rs.core.UriBuilder;
-
-/**
- * How to manufacture URIs to workflow runs.
- * 
- * @author Donal Fellows
- */
-public interface UriBuilderFactory {
-	/**
-	 * Given a run, get a factory for RESTful URIs to resources associated
-	 * with it.
-	 * 
-	 * @param run
-	 *            The run in question.
-	 * @return The {@link URI} factory.
-	 */
-	UriBuilder getRunUriBuilder(TavernaRun run);
-
-	/**
-	 * @return a URI factory that is preconfigured to point to the base of
-	 *         the webapp.
-	 */
-	UriBuilder getBaseUriBuilder();
-
-	/**
-	 * Resolves a URI with respect to the base URI of the factory.
-	 * 
-	 * @param uri
-	 *            The URI to resolve, or <tt>null</tt>.
-	 * @return The resolved URI, or <tt>null</tt> if <b>uri</b> is
-	 *         <tt>null</tt>.
-	 */
-	String resolve(String uri);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
deleted file mode 100644
index cfbbe79..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/interfaces/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Interfaces to the main worker classes that provide the magical power
- * that drives the webapp front-end.
- */
-package org.taverna.server.master.interfaces;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
deleted file mode 100644
index fc7f881..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/AbstractRemoteRunFactory.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import static java.lang.System.getSecurityManager;
-import static java.lang.System.setProperty;
-import static java.lang.System.setSecurityManager;
-import static java.rmi.registry.LocateRegistry.createRegistry;
-import static java.rmi.registry.LocateRegistry.getRegistry;
-import static java.rmi.registry.Registry.REGISTRY_PORT;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.DIR;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.net.URI;
-import java.net.URL;
-import java.rmi.MarshalledObject;
-import java.rmi.RMISecurityManager;
-import java.rmi.RemoteException;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.Resource;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.notification.atom.EventDAO;
-import org.taverna.server.master.usage.UsageRecordRecorder;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.worker.FactoryBean;
-import org.taverna.server.master.worker.RemoteRunDelegate;
-import org.taverna.server.master.worker.RunFactoryConfiguration;
-
-import uk.org.taverna.scufl2.api.io.WriterException;
-
-/**
- * Bridge to remote runs via RMI.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs")
-public abstract class AbstractRemoteRunFactory extends RunFactoryConfiguration
-		implements ListenerFactory, RunFactory, FactoryBean {
-	/**
-	 * Whether to apply stronger limitations than normal to RMI. It is
-	 * recommended that this be true!
-	 */
-	@Value("${rmi.localhostOnly}")
-	private boolean rmiLocalhostOnly;
-	/** The interaction host name. */
-	private String interhost;
-	/** The interaction port number. */
-	private String interport;
-	private Process registryProcess;
-	/**
-	 * The interaction WebDAV location. Will be resolved before being passed to
-	 * the back-end.
-	 */
-	private String interwebdav;
-	/**
-	 * The interaction ATOM feed location. Will be resolved before being passed
-	 * to the back-end.
-	 */
-	private String interfeed;
-	/** Used for doing URI resolution. */
-	@Resource(name = "webapp")
-	private UriBuilderFactory baseurifactory;
-	@Autowired
-	private InteractionFeedSupport interactionFeedSupport;
-
-	@Value("${taverna.interaction.host}")
-	void setInteractionHost(String host) {
-		if (host != null && host.equals("none"))
-			host = null;
-		interhost = host;
-	}
-
-	@Value("${taverna.interaction.port}")
-	void setInteractionPort(String port) {
-		if (port != null && port.equals("none"))
-			port = null;
-		interport = port;
-	}
-
-	@Value("${taverna.interaction.webdav_path}")
-	void setInteractionWebdav(String webdav) {
-		if (webdav != null && webdav.equals("none"))
-			webdav = null;
-		interwebdav = webdav;
-	}
-
-	@Value("${taverna.interaction.feed_path}")
-	void setInteractionFeed(String feed) {
-		if (feed != null && feed.equals("none"))
-			feed = null;
-		interfeed = feed;
-	}
-
-	@Override
-	protected void reinitRegistry() {
-		registry = null;
-		if (registryProcess != null) {
-			registryProcess.destroy();
-			registryProcess = null;
-		}
-	}
-
-	protected void initInteractionDetails(RemoteRunFactory factory)
-			throws RemoteException {
-		if (interhost != null) {
-			String feed = baseurifactory.resolve(interfeed);
-			String webdav = baseurifactory.resolve(interwebdav);
-			factory.setInteractionServiceDetails(interhost, interport, webdav,
-					feed);
-		}
-	}
-
-	protected static final Process launchSubprocess(ProcessBuilder b)
-			throws IOException {
-		Thread t = Thread.currentThread();
-		ClassLoader ccl = t.getContextClassLoader();
-		try {
-			t.setContextClassLoader(null);
-			return b.start();
-		} finally {
-			t.setContextClassLoader(ccl);
-		}
-	}
-
-	/** Get a handle to a new instance of the RMI registry. */
-	private Registry makeRegistry(int port) throws RemoteException {
-		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
-		p.command().add("-jar");
-		p.command().add(getRmiRegistryJar());
-		p.command().add(Integer.toString(port));
-		p.command().add(Boolean.toString(rmiLocalhostOnly));
-		try {
-			Process proc = launchSubprocess(p);
-			Thread.sleep(getSleepTime());
-			try {
-				if (proc.exitValue() == 0)
-					return null;
-				String error = IOUtils.toString(proc.getErrorStream());
-				throw new RemoteException(error);
-			} catch (IllegalThreadStateException ise) {
-				// Still running!
-			}
-			try (ObjectInputStream ois = new ObjectInputStream(
-					proc.getInputStream())) {
-				@SuppressWarnings("unchecked")
-				Registry r = ((MarshalledObject<Registry>) ois.readObject())
-						.get();
-				registryProcess = proc;
-				return r;
-			}
-		} catch (RemoteException e) {
-			throw e;
-		} catch (ClassNotFoundException e) {
-			throw new RemoteException("unexpected registry type", e);
-		} catch (IOException e) {
-			throw new RemoteException("unexpected IO problem with registry", e);
-		} catch (InterruptedException e) {
-			throw new RemoteException("unexpected interrupt");
-		}
-	}
-
-	/**
-	 * @return A handle to the current RMI registry.
-	 */
-	protected Registry getTheRegistry() {
-		try {
-			if (registry != null) {
-				registry.list();
-				return registry;
-			}
-		} catch (RemoteException e) {
-			log.warn("non-functioning existing registry handle", e);
-			registry = null;
-		}
-		try {
-			registry = getRegistry(getRegistryHost(), getRegistryPort());
-			registry.list();
-			return registry;
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle.");
-			registry = null;
-			log.warn("Will build new registry, "
-					+ "but service restart ability is at risk.");
-			try {
-				registry = makeRegistry(getRegistryPort());
-				registry.list();
-				return registry;
-			} catch (RemoteException e2) {
-				log.error(
-						"failed to create local working RMI registry on port "
-								+ getRegistryPort(), e2);
-				log.info("original connection exception", e);
-			}
-		}
-		try {
-			registry = getRegistry(getRegistryHost(), REGISTRY_PORT);
-			registry.list();
-			return registry;
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle on backup port.");
-			try {
-				registry = makeRegistry(REGISTRY_PORT);
-				registry.list();
-				return registry;
-			} catch (RemoteException e2) {
-				log.fatal(
-						"totally failed to get registry handle, even on fallback!",
-						e2);
-				log.info("original connection exception", e);
-				registry = null;
-				throw new RuntimeException("No RMI Registry Available");
-			}
-		}
-	}
-
-	private Registry registry;
-	/**
-	 * The name of the resource that describes the default security policy to
-	 * install.
-	 */
-	public static final String SECURITY_POLICY_FILE = "security.policy";
-	private SecurityContextFactory securityFactory;
-	UsageRecordRecorder usageRecordSink;
-	private EventDAO masterEventFeed;
-
-	@Autowired(required = true)
-	void setSecurityContextFactory(SecurityContextFactory factory) {
-		this.securityFactory = factory;
-	}
-
-	@Autowired(required = true)
-	void setMasterEventFeed(EventDAO masterEventFeed) {
-		this.masterEventFeed = masterEventFeed;
-	}
-
-	@Autowired(required = true)
-	void setUsageRecordSink(UsageRecordRecorder usageRecordSink) {
-		this.usageRecordSink = usageRecordSink;
-	}
-
-	/**
-	 * Configures the Java security model. Not currently used, as it is
-	 * viciously difficult to get right!
-	 */
-	@SuppressWarnings("unused")
-	private static void installSecurityManager() {
-		if (getSecurityManager() == null) {
-			setProperty("java.security.policy", AbstractRemoteRunFactory.class
-					.getClassLoader().getResource(SECURITY_POLICY_FILE)
-					.toExternalForm());
-			setSecurityManager(new RMISecurityManager());
-		}
-	}
-
-	// static {
-	// installSecurityManager();
-	// }
-
-	/**
-	 * Set up the run expiry management engine.
-	 * 
-	 * @throws JAXBException
-	 */
-	public AbstractRemoteRunFactory() throws JAXBException {
-		try {
-			registry = LocateRegistry.getRegistry();
-			registry.list();
-		} catch (RemoteException e) {
-			log.warn("Failed to get working RMI registry handle.");
-			log.warn("Will build new registry, but service restart ability is at risk.");
-			try {
-				registry = createRegistry(REGISTRY_PORT);
-				registry.list();
-			} catch (RemoteException e2) {
-				log.error("failed to create working RMI registry", e2);
-				log.info("original connection exception", e);
-			}
-		}
-	}
-
-	@Override
-	public List<String> getSupportedListenerTypes() {
-		try {
-			RemoteRunDelegate rrd = runDB.pickArbitraryRun();
-			if (rrd != null)
-				return rrd.getListenerTypes();
-			log.warn("no remote runs; no listener types");
-		} catch (Exception e) {
-			log.warn("failed to get list of listener types", e);
-		}
-		return new ArrayList<>();
-	}
-
-	@Override
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException {
-		if (run instanceof RemoteRunDelegate)
-			return ((RemoteRunDelegate) run).makeListener(listenerType,
-					configuration);
-		throw new NoListenerException("unexpected run type: " + run.getClass());
-	}
-
-	@Override
-	public TavernaRun create(UsernamePrincipal creator, Workflow workflow)
-			throws NoCreateException {
-		try {
-			Date now = new Date();
-			UUID id = randomUUID();
-			RemoteSingleRun rsr = getRealRun(creator, workflow, id);
-			RemoteRunDelegate run = new RemoteRunDelegate(now, workflow, rsr,
-					state.getDefaultLifetime(), runDB, id,
-					state.getGenerateProvenance(), this);
-			run.setSecurityContext(securityFactory.create(run, creator));
-			@Nonnull
-			URI feed = interactionFeedSupport.getFeedURI(run);
-			@Nonnull
-			URL feedUrl = feed.toURL();
-			@Nonnull
-			URL webdavUrl = baseurifactory.getRunUriBuilder(run)
-					.path(DIR + "/interactions").build().toURL();
-			@Nullable
-			URL pub = interactionFeedSupport.getLocalFeedBase(feed);
-			rsr.setInteractionServiceDetails(feedUrl, webdavUrl, pub);
-			return run;
-		} catch (NoCreateException e) {
-			log.warn("failed to build run instance", e);
-			throw e;
-		} catch (Exception e) {
-			log.warn("failed to build run instance", e);
-			throw new NoCreateException("failed to build run instance", e);
-		}
-	}
-
-	/**
-	 * Gets the RMI connector for a new run.
-	 * 
-	 * @param creator
-	 *            Who is creating the workflow run.
-	 * @param workflow
-	 *            What workflow are they instantiating.
-	 * @param id
-	 *            The identity token for the run, newly minted.
-	 * @return The remote interface to the run.
-	 * @throws Exception
-	 *             Just about anything can go wrong...
-	 */
-	protected abstract RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception;
-
-	/**
-	 * How to convert a wrapped workflow into XML.
-	 * 
-	 * @param workflow
-	 *            The wrapped workflow.
-	 * @return The XML version of the document.
-	 * @throws JAXBException
-	 *             If serialization fails.
-	 */
-	protected byte[] serializeWorkflow(Workflow workflow) throws JAXBException {
-		try {
-			return workflow.getScufl2Bytes();
-		} catch (IOException e) {
-			throw new JAXBException("problem converting to scufl2", e);
-		} catch (WriterException e) {
-			throw new JAXBException("problem converting to scufl2", e);
-		}
-	}
-
-	private void acceptUsageRecord(String usageRecord) {
-		if (usageRecordSink != null)
-			usageRecordSink.storeUsageRecord(usageRecord);
-		runDB.checkForFinishNow();
-	}
-
-	/**
-	 * Make a Remote object that can act as a consumer for usage records.
-	 * 
-	 * @param creator
-	 * 
-	 * @return The receiver, or <tt>null</tt> if the construction fails.
-	 */
-	protected UsageRecordReceiver makeURReciver(UsernamePrincipal creator) {
-		try {
-			@SuppressWarnings("serial")
-			class URReceiver extends UnicastRemoteObject implements
-					UsageRecordReceiver {
-				public URReceiver() throws RemoteException {
-					super();
-				}
-
-				@Override
-				public void acceptUsageRecord(String usageRecord) {
-					AbstractRemoteRunFactory.this.acceptUsageRecord(usageRecord);
-				}
-			}
-			return new URReceiver();
-		} catch (RemoteException e) {
-			log.warn("failed to build usage record receiver", e);
-			return null;
-		}
-	}
-
-	@Override
-	public EventDAO getMasterEventFeed() {
-		return masterEventFeed;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
deleted file mode 100644
index b67e121..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/ForkRunFactory.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import static java.lang.System.getProperty;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-import static java.util.Calendar.SECOND;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-
-import java.io.File;
-import java.rmi.ConnectException;
-import java.rmi.ConnectIOException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.Calendar;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A simple factory for workflow runs that forks runs from a subprocess.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for simple singleton forked run.")
-public class ForkRunFactory extends AbstractRemoteRunFactory implements
-		ConfigurableRunFactory {
-	private int lastStartupCheckCount;
-	private Integer lastExitCode;
-	private RemoteRunFactory factory;
-	private Process factoryProcess;
-	private String factoryProcessName;
-
-	/**
-	 * Create a factory for remote runs that works by forking off a subprocess.
-	 * 
-	 * @throws JAXBException
-	 *             Shouldn't happen.
-	 */
-	public ForkRunFactory() throws JAXBException {
-	}
-
-	@PostConstruct
-	protected void initRegistry() {
-		log.info("waiting for availability of default RMI registry");
-		getTheRegistry();
-	}
-
-	@Override
-	protected void reinitFactory() {
-		boolean makeFactory = factory != null;
-		killFactory();
-		try {
-			if (makeFactory)
-				initFactory();
-		} catch (Exception e) {
-			log.fatal("failed to make connection to remote run factory", e);
-		}
-	}
-
-	private RemoteRunFactory getFactory() throws RemoteException {
-		try {
-			initFactory();
-		} catch (RemoteException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new RemoteException("problem constructing factory", e);
-		}
-		return factory;
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	@Override
-	public int getLastStartupCheckCount() {
-		return lastStartupCheckCount;
-	}
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	@Override
-	public Integer getLastExitCode() {
-		return lastExitCode;
-	}
-
-	/**
-	 * @return What the factory subprocess's main RMI interface is registered
-	 *         as.
-	 */
-	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
-	@Override
-	public String getFactoryProcessName() {
-		return factoryProcessName;
-	}
-
-	/**
-	 * Makes the subprocess that manufactures runs.
-	 * 
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	public void initFactory() throws Exception {
-		if (factory != null)
-			return;
-		// Generate the arguments to use when spawning the subprocess
-		factoryProcessName = state.getFactoryProcessNamePrefix() + randomUUID();
-		ProcessBuilder p = new ProcessBuilder(getJavaBinary());
-		p.command().add("-jar");
-		p.command().add(getServerWorkerJar());
-		if (getExecuteWorkflowScript() == null)
-			log.fatal("no execute workflow script");
-		p.command().add(getExecuteWorkflowScript());
-		p.command().addAll(asList(getExtraArguments()));
-		p.command().add(factoryProcessName);
-		p.redirectErrorStream(true);
-		p.directory(new File(getProperty("javax.servlet.context.tempdir",
-				getProperty("java.io.tmpdir"))));
-
-		// Spawn the subprocess
-		log.info("about to create subprocess: " + p.command());
-		
-		factoryProcess = launchSubprocess(p);
-		outlog = new StreamLogger("FactoryStdout", factoryProcess.getInputStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-		errlog = new StreamLogger("FactoryStderr", factoryProcess.getErrorStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-
-		// Wait for the subprocess to register itself in the RMI registry
-		Calendar deadline = Calendar.getInstance();
-		deadline.add(SECOND, state.getWaitSeconds());
-		Exception lastException = null;
-		lastStartupCheckCount = 0;
-		while (deadline.after(Calendar.getInstance())) {
-			try {
-				sleep(state.getSleepMS());
-				lastStartupCheckCount++;
-				factory = getRemoteFactoryHandle(factoryProcessName);
-				initInteractionDetails(factory);
-				return;
-			} catch (InterruptedException ie) {
-				continue;
-			} catch (NotBoundException nbe) {
-				lastException = nbe;
-				log.info("resource \"" + factoryProcessName
-						+ "\" not yet registered...");
-				continue;
-			} catch (RemoteException re) {
-				// Unpack a remote exception if we can
-				lastException = re;
-				try {
-					if (re.getCause() != null)
-						lastException = (Exception) re.getCause();
-				} catch (Throwable t) {
-					// Ignore!
-				}
-			} catch (RuntimeException e) {
-				lastException = e;
-			}
-		}
-		if (lastException == null)
-			lastException = new InterruptedException();
-		throw lastException;
-	}
-
-	private StreamLogger outlog, errlog;
-
-	private void stopLoggers() {
-		if (outlog != null)
-			outlog.stop();
-		outlog = null;
-		if (errlog != null)
-			errlog.stop();
-		errlog = null;
-	}
-
-	private RemoteRunFactory getRemoteFactoryHandle(String name)
-			throws RemoteException, NotBoundException {
-		log.info("about to look up resource called " + name);
-		try {
-			// Validate registry connection first
-			getTheRegistry().list();
-		} catch (ConnectException | ConnectIOException e) {
-			log.warn("connection problems with registry", e);
-		}
-		RemoteRunFactory rrf = (RemoteRunFactory) getTheRegistry().lookup(name);
-		log.info("successfully connected to factory subprocess "
-				+ factoryProcessName);
-		return rrf;
-	}
-
-	/**
-	 * Destroys the subprocess that manufactures runs.
-	 */
-	@PreDestroy
-	public void killFactory() {
-		if (factory != null) {
-			log.info("requesting shutdown of " + factoryProcessName);
-			try {
-				factory.shutdown();
-				sleep(700);
-			} catch (RemoteException e) {
-				log.warn(factoryProcessName + " failed to shut down nicely", e);
-			} catch (InterruptedException e) {
-				if (log.isDebugEnabled())
-					log.debug("interrupted during wait after asking "
-							+ factoryProcessName + " to shut down", e);
-			} finally {
-				factory = null;
-			}
-		}
-
-		if (factoryProcess != null) {
-			int code = -1;
-			try {
-				lastExitCode = code = factoryProcess.exitValue();
-				log.info(factoryProcessName + " already dead?");
-			} catch (RuntimeException e) {
-				log.info("trying to force death of " + factoryProcessName);
-				try {
-					factoryProcess.destroy();
-					sleep(350); // takes a little time, even normally
-					lastExitCode = code = factoryProcess.exitValue();
-				} catch (Exception e2) {
-					code = -1;
-				}
-			} finally {
-				factoryProcess = null;
-				stopLoggers();
-			}
-			if (code > 128) {
-				log.info(factoryProcessName + " died with signal="
-						+ (code - 128));
-			} else if (code >= 0) {
-				log.info(factoryProcessName + " process killed: code=" + code);
-			} else {
-				log.warn(factoryProcessName + " not yet dead");
-			}
-		}
-	}
-
-	/**
-	 * The real core of the run builder, factored out from its reliability
-	 * support.
-	 * 
-	 * @param creator
-	 *            Who created this workflow?
-	 * @param wf
-	 *            The serialized workflow.
-	 * @return The remote handle of the workflow run.
-	 * @throws RemoteException
-	 *             If anything fails (communications error, etc.)
-	 */
-	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
-			@Nonnull byte[] wf, UUID id) throws RemoteException {
-		@Nonnull
-		String globaluser = "Unknown Person";
-		if (creator != null)
-			globaluser = creator.getName();
-		RemoteSingleRun rsr = getFactory().make(wf, globaluser,
-				makeURReciver(creator), id);
-		incrementRunCount();
-		return rsr;
-	}
-
-	@Override
-	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception {
-		@Nonnull
-		byte[] wf = serializeWorkflow(workflow);
-		for (int i = 0; i < 3; i++) {
-			initFactory();
-			try {
-				return getRealRun(creator, wf, id);
-			} catch (ConnectException | ConnectIOException e) {
-				// factory was lost; try to recreate
-			}
-			killFactory();
-		}
-		throw new NoCreateException("total failure to connect to factory "
-				+ factoryProcessName + "despite attempting restart");
-	}
-
-	@Override
-	public String[] getFactoryProcessMapping() {
-		return new String[0];
-	}
-
-	@Override
-	protected int operatingCount() throws Exception {
-		return getFactory().countOperatingRuns();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
deleted file mode 100644
index e449373..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/IdAwareForkRunFactory.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import static java.lang.System.getProperty;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-import static java.util.Calendar.SECOND;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-import static org.taverna.server.master.localworker.AbstractRemoteRunFactory.launchSubprocess;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.rmi.ConnectException;
-import java.rmi.ConnectIOException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.core.annotation.Order;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.interfaces.LocalIdentityMapper;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A simple factory for workflow runs that forks runs from a subprocess.
- * 
- * @author Donal Fellows
- */
-@ManagedResource(objectName = JMX_ROOT + "RunFactory", description = "The factory for a user-specific forked run.")
-public class IdAwareForkRunFactory extends AbstractRemoteRunFactory implements
-		ConfigurableRunFactory {
-	private MetaFactory forker;
-	private Map<String, RemoteRunFactory> factory;
-	private Map<String, String> factoryProcessName;
-
-	/**
-	 * Create a factory for remote runs that works by forking off a subprocess.
-	 * 
-	 * @throws JAXBException
-	 *             Shouldn't happen.
-	 */
-	public IdAwareForkRunFactory() throws JAXBException {
-		factory = new HashMap<>();
-		factoryProcessName = new HashMap<>();
-	}
-
-	@Override
-	protected void reinitFactory() {
-		boolean makeForker = forker != null;
-		try {
-			killForker();
-		} catch (Exception e) {
-			log.warn("exception when killing secure-fork process", e);
-		}
-		try {
-			if (makeForker)
-				initMetaFactory();
-		} catch (Exception e) {
-			log.fatal("failed to make secure-fork process", e);
-		}
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	public int getLastStartupCheckCount() {
-		return forker == null ? 0 : forker.lastStartupCheckCount();
-	}
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@Override
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	public Integer getLastExitCode() {
-		return forker == null ? null : forker.lastExitCode();
-	}
-
-	/**
-	 * @return The mapping of user names to RMI factory IDs.
-	 */
-	@Override
-	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
-	public String[] getFactoryProcessMapping() {
-		ArrayList<String> result = new ArrayList<>();
-		ArrayList<String> keys = new ArrayList<>(factoryProcessName.keySet());
-		String[] ks = keys.toArray(new String[keys.size()]);
-		Arrays.sort(ks);
-		for (String k : ks) {
-			result.add(k);
-			result.add(factoryProcessName.get(k));
-		}
-		return result.toArray(new String[result.size()]);
-	}
-
-	/**
-	 * How construction of factories is actually done.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public interface MetaFactory {
-		/**
-		 * Make a factory for the given user.
-		 * 
-		 * @param username
-		 *            Who to make it for.
-		 * @return Handle of the factory.
-		 * @throws Exception
-		 *             If anything goes wrong.
-		 */
-		RemoteRunFactory make(String username) throws Exception;
-
-		/**
-		 * Shut down the meta-factory. It is not defined whether factories
-		 * created by it are also shut down at the same time.
-		 * 
-		 * @throws IOException
-		 *             If something goes wrong when communicating with the
-		 *             meta-factory.
-		 * @throws InterruptedException
-		 *             If something stops us waiting for the shut down to
-		 *             happen.
-		 */
-		void close() throws IOException, InterruptedException;
-
-		int lastStartupCheckCount();
-
-		Integer lastExitCode();
-	}
-
-	void registerFactory(String username, String fpn, RemoteRunFactory f) {
-		factoryProcessName.put(username, fpn);
-		factory.put(username, f);
-	}
-
-	/**
-	 * Makes the connection to the meta-factory that makes factories.
-	 * 
-	 * @throws IOException
-	 *             If the connection fails.
-	 */
-	@PostConstruct
-	void initMetaFactory() throws IOException {
-		log.info("waiting for availability of default RMI registry");
-		getTheRegistry();
-		log.info("constructing secure fork subprocess");
-		forker = new SecureFork(this, state, log);
-	}
-
-	private void killForker() throws IOException, InterruptedException {
-		try {
-			if (forker != null)
-				forker.close();
-		} finally {
-			forker = null;
-		}
-	}
-
-	/**
-	 * Makes the subprocess that manufactures runs.
-	 * 
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	private void initFactory(String username) throws Exception {
-		if (factory.containsKey(username))
-			return;
-		if (forker == null)
-			initMetaFactory();
-		forker.make(username);
-	}
-
-	/**
-	 * Destroys the subprocess that manufactures runs.
-	 */
-	@PreDestroy
-	public void killFactories() {
-		if (!factory.isEmpty()) {
-			Iterator<String> keys = factory.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				log.info("requesting shutdown of "
-						+ factoryProcessName.get(key));
-				try {
-					factory.get(key).shutdown();
-				} catch (RemoteException e) {
-					log.warn(factoryProcessName.get(key)
-							+ " failed to shut down nicely", e);
-				} finally {
-					keys.remove();
-					factoryProcessName.remove(key);
-				}
-			}
-			try {
-				sleep(700);
-			} catch (InterruptedException e) {
-				if (log.isDebugEnabled())
-					log.debug("interrupted during wait after "
-							+ "asking factories to shut down", e);
-			}
-		}
-
-		try {
-			killForker();
-		} catch (Exception e) {
-			if (log.isDebugEnabled())
-				log.debug("exception in shutdown of secure-fork process", e);
-		}
-	}
-
-	@Override
-	protected void finalize() throws Throwable {
-		killFactories();
-		super.finalize();
-	}
-
-	@Autowired
-	public void setIdMapper(LocalIdentityMapper mapper) {
-		this.mapper = mapper;
-	}
-
-	private LocalIdentityMapper mapper;
-
-	/**
-	 * The real core of the run builder, factored out from its reliability
-	 * support.
-	 * 
-	 * @param creator
-	 *            Who created this workflow?
-	 * @param username
-	 *            What user account is this workflow to be executed in?
-	 * @param wf
-	 *            The serialized workflow.
-	 * @return The remote handle of the workflow run.
-	 * @throws RemoteException
-	 *             If anything fails (communications error, etc.)
-	 */
-	private RemoteSingleRun getRealRun(@Nonnull UsernamePrincipal creator,
-			@Nonnull String username, @Nonnull byte[] wf, UUID id)
-			throws RemoteException {
-		String globaluser = "Unknown Person";
-		if (creator != null)
-			globaluser = creator.getName();
-		RemoteSingleRun rsr = factory.get(username).make(wf, globaluser,
-				makeURReciver(creator), id);
-		incrementRunCount();
-		return rsr;
-	}
-
-	@Override
-	protected RemoteSingleRun getRealRun(UsernamePrincipal creator,
-			Workflow workflow, UUID id) throws Exception {
-		byte[] wf = serializeWorkflow(workflow);
-		String username = mapper == null ? null : mapper
-				.getUsernameForPrincipal(creator);
-		if (username == null)
-			throw new Exception("cannot determine who to run workflow as; "
-					+ "local identity mapper returned null");
-		for (int i = 0; i < 3; i++) {
-			if (!factory.containsKey(username))
-				initFactory(username);
-			try {
-				return getRealRun(creator, username, wf, id);
-			} catch (ConnectException | ConnectIOException e) {
-				// factory was lost; try to recreate
-			}
-			factory.remove(username);
-		}
-		throw new NoCreateException("total failure to connect to factory "
-				+ factoryProcessName + "despite attempting restart");
-	}
-
-	@Value("${secureForkPasswordFile}")
-	@Order(20)
-	public void setPasswordSource(String passwordSource) {
-		if (passwordSource == null || passwordSource.isEmpty()
-				|| passwordSource.startsWith("${"))
-			state.setDefaultPasswordFile(null);
-		else
-			state.setDefaultPasswordFile(passwordSource);
-		if (state.getPasswordFile() == null)
-			log.info("assuming password-free forking enabled");
-		else
-			log.info("configured secureForkPasswordFile from context as "
-					+ state.getPasswordFile());
-	}
-
-	@Override
-	public String getFactoryProcessName() {
-		return "<PROPERTY-NOT-SUPPORTED>";
-	}
-
-	@Override
-	protected int operatingCount() throws Exception {
-		int total = 0;
-		for (RemoteRunFactory rrf : factory.values())
-			total += rrf.countOperatingRuns();
-		return total;
-	}
-}
-
-/**
- * The connector that handles the secure fork process itself.
- * 
- * @author Donal Fellows
- */
-class SecureFork implements IdAwareForkRunFactory.MetaFactory {
-	private IdAwareForkRunFactory main;
-	private Process process;
-	private PrintWriter channel;
-	private int lastStartupCheckCount;
-	private Integer lastExitCode;
-	private Log log;
-	private LocalWorkerState state;
-	private StreamLogger out, err;
-
-	/**
-	 * Construct the command to run the meta-factory process.
-	 * 
-	 * @param args
-	 *            The live list of arguments to pass.
-	 */
-	public void initFactoryArgs(List<String> args) {
-		args.add(main.getJavaBinary());
-		String pwf = main.getPasswordFile();
-		if (pwf != null) {
-			args.add("-Dpassword.file=" + pwf);
-		}
-		args.add("-jar");
-		args.add(main.getServerForkerJar());
-		args.add(main.getJavaBinary());
-		args.add("-jar");
-		args.add(main.getServerWorkerJar());
-		if (main.getExecuteWorkflowScript() == null)
-			log.fatal("no execute workflow script");
-		args.add(main.getExecuteWorkflowScript());
-		args.addAll(asList(main.getExtraArguments()));
-	}
-
-	SecureFork(IdAwareForkRunFactory main, LocalWorkerState state, Log log)
-			throws IOException {
-		this.main = main;
-		this.log = log;
-		this.state = state;
-		ProcessBuilder p = new ProcessBuilder();
-		initFactoryArgs(p.command());
-		p.redirectErrorStream(true);
-		p.directory(new File(getProperty("javax.servlet.context.tempdir",
-				getProperty("java.io.tmpdir"))));
-
-		// Spawn the subprocess
-		log.info("about to create subprocess: " + p.command());
-		log.info("subprocess directory: " + p.directory());
-		process = launchSubprocess(p);
-		channel = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
-				process.getOutputStream())), true);
-		// Log the responses
-		out = new StreamLogger("ForkedStdout", process.getInputStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-		err = new StreamLogger("ForkedStderr", process.getErrorStream()) {
-			@Override
-			protected void write(String msg) {
-				log.info(msg);
-			}
-		};
-	}
-
-	@Override
-	public void close() throws IOException, InterruptedException {
-		try {
-			if (process != null) {
-				log.info("about to close down subprocess");
-				channel.close();
-				int code = -1;
-				try {
-					try {
-						code = process.exitValue();
-						log.info("secure-fork process already dead?");
-					} catch (IllegalThreadStateException e) {
-						try {
-							code = process.waitFor();
-						} catch (InterruptedException e1) {
-							log.info("interrupted waiting for natural death of secure-fork process?!");
-							process.destroy();
-							code = process.waitFor();
-						}
-					}
-				} finally {
-					lastExitCode = code;
-					if (code > 128) {
-						log.info("secure-fork process died with signal="
-								+ (code - 128));
-					} else if (code >= 0) {
-						log.info("secure-fork process killed: code=" + code);
-					} else {
-						log.warn("secure-fork process not yet dead");
-					}
-				}
-			}
-		} finally {
-			process = null;
-			channel = null;
-			out.stop();
-			err.stop();
-		}
-	}
-
-	protected void make(String username, String fpn) {
-		log.info("about to request subprocess creation for " + username
-				+ " producing ID " + fpn);
-		channel.println(username + " " + fpn);
-	}
-
-	@Override
-	public RemoteRunFactory make(String username) throws Exception {
-		try {
-			main.getTheRegistry().list(); // Validate registry connection first
-		} catch (ConnectException | ConnectIOException e) {
-			log.warn("connection problems with registry", e);
-		} catch (RemoteException e) {
-			if (e.getCause() != null && e.getCause() instanceof Exception) {
-				throw (Exception) e.getCause();
-			}
-			log.warn("connection problems with registry", e);
-		}
-
-		String fpn = state.getFactoryProcessNamePrefix() + randomUUID();
-		make(username, fpn);
-
-		// Wait for the subprocess to register itself in the RMI registry
-		Calendar deadline = Calendar.getInstance();
-		deadline.add(SECOND, state.getWaitSeconds());
-		Exception lastException = null;
-		lastStartupCheckCount = 0;
-		while (deadline.after(Calendar.getInstance())) {
-			try {
-				sleep(state.getSleepMS());
-				lastStartupCheckCount++;
-				log.info("about to look up resource called " + fpn);
-				RemoteRunFactory f = (RemoteRunFactory) main.getTheRegistry()
-						.lookup(fpn);
-				log.info("successfully connected to factory subprocess " + fpn);
-				main.initInteractionDetails(f);
-				main.registerFactory(username, fpn, f);
-				return f;
-			} catch (InterruptedException ie) {
-				continue;
-			} catch (NotBoundException nbe) {
-				lastException = nbe;
-				log.info("resource \"" + fpn + "\" not yet registered...");
-				continue;
-			} catch (RemoteException re) {
-				// Unpack a remote exception if we can
-				lastException = re;
-				try {
-					if (re.getCause() != null)
-						lastException = (Exception) re.getCause();
-				} catch (Throwable t) {
-					// Ignore!
-				}
-			} catch (Exception e) {
-				lastException = e;
-			}
-		}
-		if (lastException == null)
-			lastException = new InterruptedException();
-		throw lastException;
-	}
-
-	@Override
-	public Integer lastExitCode() {
-		return lastExitCode;
-	}
-
-	@Override
-	public int lastStartupCheckCount() {
-		return lastStartupCheckCount;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
deleted file mode 100644
index f890204..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * Provider of the configuration of the "localworker.factory" bean, which is
- * sufficiently complex to be too hard to manufacture directly from the XML
- * configuration.
- * 
- * @author Donal Fellows
- */
-@Configuration
-public class LocalWorkerFactory {
-	@Bean(name = "localworker.factory")
-	AbstractRemoteRunFactory getLocalworkerFactory(
-			@Value("${backEndFactory}") String mode) throws Exception {
-		if (mode == null || mode.isEmpty() || mode.startsWith("${"))
-			throw new Exception("no value for ${backEndFactory}");
-		Class<?> c = Class.forName(mode);
-		if (AbstractRemoteRunFactory.class.isAssignableFrom(c))
-			return (AbstractRemoteRunFactory) c.newInstance();
-		throw new Exception("unknown remote run factory: " + mode);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
deleted file mode 100644
index 9f0f39b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/LocalWorkerState.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import static java.io.File.separator;
-import static java.lang.System.getProperty;
-import static java.rmi.registry.Registry.REGISTRY_PORT;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.unmodifiableList;
-import static org.taverna.server.master.defaults.Default.EXTRA_ARGUMENTS;
-import static org.taverna.server.master.defaults.Default.PASSWORD_FILE;
-import static org.taverna.server.master.defaults.Default.REGISTRY_JAR;
-import static org.taverna.server.master.defaults.Default.RMI_PREFIX;
-import static org.taverna.server.master.defaults.Default.RUN_LIFE_MINUTES;
-import static org.taverna.server.master.defaults.Default.RUN_OPERATING_LIMIT;
-import static org.taverna.server.master.defaults.Default.SECURE_FORK_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SERVER_WORKER_IMPLEMENTATION_JAR;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_POLL_SLEEP;
-import static org.taverna.server.master.defaults.Default.SUBPROCESS_START_WAIT;
-import static org.taverna.server.master.localworker.PersistedState.KEY;
-import static org.taverna.server.master.localworker.PersistedState.makeInstance;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.net.URI;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.defaults.Default;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The persistent state of a local worker factory.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class LocalWorkerState extends JDOSupport<PersistedState> implements
-		WorkerModel {
-	public LocalWorkerState() {
-		super(PersistedState.class);
-	}
-
-	private LocalWorkerState self;
-
-	@Required
-	public void setSelf(LocalWorkerState self) {
-		this.self = self;
-	}
-
-	/** Initial lifetime of runs, in minutes. */
-	int defaultLifetime;
-	/**
-	 * Maximum number of runs to exist at once. Note that this includes when
-	 * they are just existing for the purposes of file transfer (
-	 * {@link Status#Initialized}/{@link Status#Finished} states).
-	 */
-	int maxRuns;
-	/**
-	 * Prefix to use for RMI names.
-	 */
-	String factoryProcessNamePrefix;
-	/**
-	 * Full path name of the script used to start running a workflow; normally
-	 * expected to be "<i>somewhere/</i><tt>executeWorkflow.sh</tt>".
-	 */
-	String executeWorkflowScript;
-	/** Default value for {@link #executeWorkflowScript}. */
-	private transient String defaultExecuteWorkflowScript;
-	/**
-	 * Full path name of the file containing the password used to launch workers
-	 * as other users. The file is normally expected to contain a single line,
-	 * the password, and to be thoroughly locked down so only the user running
-	 * the server (e.g., "<tt>tomcat</tt>") can read it; it will probably reside
-	 * in either the user's home directory or in a system configuration
-	 * directory.
-	 */
-	String passwordFile;
-	/** Default value for {@link #passwordFile}. */
-	private transient String defaultPasswordFile = PASSWORD_FILE;
-	/**
-	 * The extra arguments to pass to the subprocess.
-	 */
-	String[] extraArgs;
-	/**
-	 * How long to wait for subprocess startup, in seconds.
-	 */
-	int waitSeconds;
-	/**
-	 * Polling interval to use during startup, in milliseconds.
-	 */
-	int sleepMS;
-	/**
-	 * Full path name to the worker process's implementation JAR.
-	 */
-	String serverWorkerJar;
-	private static final String DEFAULT_WORKER_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(SERVER_WORKER_IMPLEMENTATION_JAR)
-			.getFile();
-	/**
-	 * Full path name to the Java binary to use to run the subprocess.
-	 */
-	String javaBinary;
-	private static final String DEFAULT_JAVA_BINARY = getProperty("java.home")
-			+ separator + "bin" + separator + "java";
-	/**
-	 * Full path name to the secure fork process's implementation JAR.
-	 */
-	String serverForkerJar;
-	private static final String DEFAULT_FORKER_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(SECURE_FORK_IMPLEMENTATION_JAR)
-			.getFile();
-
-	String registryHost;
-	int registryPort;
-
-	int operatingLimit;
-
-	URI[] permittedWorkflows;
-	private String registryJar;
-	private static final String DEFAULT_REGISTRY_JAR = LocalWorkerState.class
-			.getClassLoader().getResource(REGISTRY_JAR).getFile();
-
-	@Override
-	public void setDefaultLifetime(int defaultLifetime) {
-		this.defaultLifetime = defaultLifetime;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getDefaultLifetime() {
-		return defaultLifetime < 1 ? RUN_LIFE_MINUTES : defaultLifetime;
-	}
-
-	@Override
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns < 1 ? Default.RUN_COUNT_MAX : maxRuns;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return operatingLimit < 1 ? RUN_OPERATING_LIMIT : operatingLimit;
-	}
-
-	@Override
-	public void setOperatingLimit(int operatingLimit) {
-		this.operatingLimit = operatingLimit;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
-		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getFactoryProcessNamePrefix() {
-		return factoryProcessNamePrefix == null ? RMI_PREFIX
-				: factoryProcessNamePrefix;
-	}
-
-	@Override
-	public void setExecuteWorkflowScript(String executeWorkflowScript) {
-		this.executeWorkflowScript = executeWorkflowScript;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getExecuteWorkflowScript() {
-		return executeWorkflowScript == null ? defaultExecuteWorkflowScript
-				: executeWorkflowScript;
-	}
-
-	private static String guessWorkflowScript() {
-		File utilDir = new File(DEFAULT_WORKER_JAR).getParentFile();
-		File[] dirs = utilDir.listFiles(new FilenameFilter() {
-			@Override
-			public boolean accept(File dir, String name) {
-				return name.startsWith("taverna-commandline-");
-			}
-		});
-		assert dirs.length > 0;
-		return new File(dirs[0], "executeworkflow.sh").toString();
-	}
-
-	/**
-	 * Set what executeworkflow script to use by default. This is the value that
-	 * is used if not overridden by the administration interface.
-	 * 
-	 * @param defaultScript
-	 *            Full path to the script to use.
-	 */
-	public void setDefaultExecuteWorkflowScript(String defaultScript) {
-		if (defaultScript.startsWith("${") || defaultScript.equals("NONE")) {
-			this.defaultExecuteWorkflowScript = guessWorkflowScript();
-			return;
-		}
-		this.defaultExecuteWorkflowScript = defaultScript;
-	}
-
-	String getDefaultExecuteWorkflowScript() {
-		return defaultExecuteWorkflowScript;
-	}
-
-	@Override
-	public void setExtraArgs(String[] extraArgs) {
-		this.extraArgs = extraArgs.clone();
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String[] getExtraArgs() {
-		return extraArgs == null ? EXTRA_ARGUMENTS : extraArgs.clone();
-	}
-
-	@Override
-	public void setWaitSeconds(int waitSeconds) {
-		this.waitSeconds = waitSeconds;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getWaitSeconds() {
-		return waitSeconds < 1 ? SUBPROCESS_START_WAIT : waitSeconds;
-	}
-
-	@Override
-	public void setSleepMS(int sleepMS) {
-		this.sleepMS = sleepMS;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getSleepMS() {
-		return sleepMS < 1 ? SUBPROCESS_START_POLL_SLEEP : sleepMS;
-	}
-
-	@Override
-	public void setServerWorkerJar(String serverWorkerJar) {
-		this.serverWorkerJar = serverWorkerJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getServerWorkerJar() {
-		return serverWorkerJar == null ? DEFAULT_WORKER_JAR : serverWorkerJar;
-	}
-
-	@Override
-	public void setServerForkerJar(String serverForkerJar) {
-		this.serverForkerJar = serverForkerJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getServerForkerJar() {
-		return serverForkerJar == null ? DEFAULT_FORKER_JAR : serverForkerJar;
-	}
-
-	@Override
-	public void setJavaBinary(String javaBinary) {
-		this.javaBinary = javaBinary;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getJavaBinary() {
-		return javaBinary == null ? DEFAULT_JAVA_BINARY : javaBinary;
-	}
-
-	@Override
-	public void setPasswordFile(String passwordFile) {
-		this.passwordFile = passwordFile;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getPasswordFile() {
-		return passwordFile == null ? defaultPasswordFile : passwordFile;
-	}
-
-	void setDefaultPasswordFile(String defaultPasswordFile) {
-		this.defaultPasswordFile = defaultPasswordFile;
-	}
-
-	@Override
-	public void setRegistryHost(String registryHost) {
-		this.registryHost = (registryHost == null ? "" : registryHost);
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public String getRegistryHost() {
-		return (registryHost == null || registryHost.isEmpty()) ? null
-				: registryHost;
-	}
-
-	@Override
-	public void setRegistryPort(int registryPort) {
-		this.registryPort = ((registryPort < 1 || registryPort > 65534) ? REGISTRY_PORT
-				: registryPort);
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public int getRegistryPort() {
-		return registryPort == 0 ? REGISTRY_PORT : registryPort;
-	}
-
-	@Override
-	public String getRegistryJar() {
-		return registryJar == null ? DEFAULT_REGISTRY_JAR : registryJar;
-	}
-
-	@Override
-	public void setRegistryJar(String rmiRegistryJar) {
-		this.registryJar = (rmiRegistryJar == null || rmiRegistryJar.isEmpty()) ? null
-				: rmiRegistryJar;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public List<URI> getPermittedWorkflowURIs() {
-		if (permittedWorkflows == null || permittedWorkflows.length == 0)
-			return emptyList();
-		return unmodifiableList(asList(permittedWorkflows));
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
-		if (permittedWorkflows == null || permittedWorkflows.isEmpty())
-			this.permittedWorkflows = new URI[0];
-		else
-			this.permittedWorkflows = permittedWorkflows
-					.toArray(new URI[permittedWorkflows.size()]);
-		if (loadedState)
-			self.store();
-	}
-
-	public static final boolean DEFAULT_GENERATE_PROVENANCE = false;
-	private Boolean generateProvenance;
-
-	@Override
-	public boolean getGenerateProvenance() {
-		Boolean g = generateProvenance;
-		return g == null ? DEFAULT_GENERATE_PROVENANCE : (boolean) g;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generate) {
-		this.generateProvenance = generate;
-		if (loadedState)
-			self.store();
-	}
-
-	// --------------------------------------------------------------
-
-	private boolean loadedState;
-
-	@PostConstruct
-	@WithinSingleTransaction
-	public void load() {
-		if (loadedState || !isPersistent())
-			return;
-		WorkerModel state = getById(KEY);
-		if (state == null) {
-			store();
-			return;
-		}
-
-		defaultLifetime = state.getDefaultLifetime();
-		executeWorkflowScript = state.getExecuteWorkflowScript();
-		extraArgs = state.getExtraArgs();
-		factoryProcessNamePrefix = state.getFactoryProcessNamePrefix();
-		javaBinary = state.getJavaBinary();
-		maxRuns = state.getMaxRuns();
-		serverWorkerJar = state.getServerWorkerJar();
-		serverForkerJar = state.getServerForkerJar();
-		passwordFile = state.getPasswordFile();
-		sleepMS = state.getSleepMS();
-		waitSeconds = state.getWaitSeconds();
-		registryHost = state.getRegistryHost();
-		registryPort = state.getRegistryPort();
-		operatingLimit = state.getOperatingLimit();
-		List<URI> pwu = state.getPermittedWorkflowURIs();
-		permittedWorkflows = (URI[]) pwu.toArray(new URI[pwu.size()]);
-		registryJar = state.getRegistryJar();
-		generateProvenance = state.getGenerateProvenance();
-
-		loadedState = true;
-	}
-
-	@WithinSingleTransaction
-	public void store() {
-		if (!isPersistent())
-			return;
-		WorkerModel state = getById(KEY);
-		if (state == null)
-			state = persist(makeInstance());
-
-		state.setDefaultLifetime(defaultLifetime);
-		state.setExecuteWorkflowScript(executeWorkflowScript);
-		state.setExtraArgs(extraArgs);
-		state.setFactoryProcessNamePrefix(factoryProcessNamePrefix);
-		state.setJavaBinary(javaBinary);
-		state.setMaxRuns(maxRuns);
-		state.setServerWorkerJar(serverWorkerJar);
-		state.setServerForkerJar(serverForkerJar);
-		state.setPasswordFile(passwordFile);
-		state.setSleepMS(sleepMS);
-		state.setWaitSeconds(waitSeconds);
-		state.setRegistryHost(registryHost);
-		state.setRegistryPort(registryPort);
-		state.setOperatingLimit(operatingLimit);
-		if (permittedWorkflows != null)
-			state.setPermittedWorkflowURIs(asList(permittedWorkflows));
-		state.setRegistryJar(registryJar);
-		if (generateProvenance != null)
-			state.setGenerateProvenance(generateProvenance);
-
-		loadedState = true;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
deleted file mode 100644
index 83d6bda..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/PersistedState.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.localworker;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jdo.annotations.Join;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-
-import org.taverna.server.master.worker.WorkerModel;
-
-/**
- * The actual database connector for persisted local worker state.
- * 
- * @author Donal Fellows
- */
-/*
- * WARNING! If you change the name of this class, update persistence.xml as
- * well!
- */
-@PersistenceCapable(table = PersistedState.TABLE)
-class PersistedState implements WorkerModel {
-	static final String TABLE = "LOCALWORKERSTATE__PERSISTEDSTATE";
-
-	static PersistedState makeInstance() {
-		PersistedState o = new PersistedState();
-		o.ID = KEY;
-		return o;
-	}
-
-	@PrimaryKey(column = "ID")
-	protected int ID;
-
-	static final int KEY = 32;
-
-	@Persistent
-	private int defaultLifetime;
-	@Persistent
-	private int maxRuns;
-	@Persistent
-	private String factoryProcessNamePrefix;
-	@Persistent
-	private String executeWorkflowScript;
-	@Persistent(serialized = "true")
-	private String[] extraArgs;
-	@Persistent
-	private int waitSeconds;
-	@Persistent
-	private int sleepMS;
-	@Persistent
-	private String serverWorkerJar;
-	@Persistent
-	private String serverForkerJar;
-	@Persistent
-	private String registryJar;
-	@Persistent
-	private String passwordFile;
-	@Persistent
-	private String javaBinary;
-	@Persistent
-	private int registryPort;
-	@Persistent
-	private String registryHost;
-	@Persistent
-	private int operatingLimit;
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_PERMWFURI", column = "ID")
-	private String[] permittedWorkflows;
-	@Persistent
-	private int generateProvenance;
-
-	@Override
-	public void setDefaultLifetime(int defaultLifetime) {
-		this.defaultLifetime = defaultLifetime;
-	}
-
-	@Override
-	public int getDefaultLifetime() {
-		return defaultLifetime;
-	}
-
-	@Override
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns;
-	}
-
-	@Override
-	public void setFactoryProcessNamePrefix(String factoryProcessNamePrefix) {
-		this.factoryProcessNamePrefix = factoryProcessNamePrefix;
-	}
-
-	@Override
-	public String getFactoryProcessNamePrefix() {
-		return factoryProcessNamePrefix;
-	}
-
-	@Override
-	public void setExecuteWorkflowScript(String executeWorkflowScript) {
-		this.executeWorkflowScript = executeWorkflowScript;
-	}
-
-	@Override
-	public String getExecuteWorkflowScript() {
-		return executeWorkflowScript;
-	}
-
-	@Override
-	public void setExtraArgs(String[] extraArgs) {
-		this.extraArgs = extraArgs;
-	}
-
-	@Override
-	public String[] getExtraArgs() {
-		return extraArgs;
-	}
-
-	@Override
-	public void setWaitSeconds(int waitSeconds) {
-		this.waitSeconds = waitSeconds;
-	}
-
-	@Override
-	public int getWaitSeconds() {
-		return waitSeconds;
-	}
-
-	@Override
-	public void setSleepMS(int sleepMS) {
-		this.sleepMS = sleepMS;
-	}
-
-	@Override
-	public int getSleepMS() {
-		return sleepMS;
-	}
-
-	@Override
-	public void setServerWorkerJar(String serverWorkerJar) {
-		this.serverWorkerJar = serverWorkerJar;
-	}
-
-	@Override
-	public String getServerWorkerJar() {
-		return serverWorkerJar;
-	}
-
-	@Override
-	public void setJavaBinary(String javaBinary) {
-		this.javaBinary = javaBinary;
-	}
-
-	@Override
-	public String getJavaBinary() {
-		return javaBinary;
-	}
-
-	@Override
-	public void setRegistryPort(int registryPort) {
-		this.registryPort = registryPort;
-	}
-
-	@Override
-	public int getRegistryPort() {
-		return registryPort;
-	}
-
-	@Override
-	public void setRegistryHost(String registryHost) {
-		this.registryHost = registryHost;
-	}
-
-	@Override
-	public String getRegistryHost() {
-		return registryHost;
-	}
-
-	@Override
-	public void setServerForkerJar(String serverForkerJar) {
-		this.serverForkerJar = serverForkerJar;
-	}
-
-	@Override
-	public String getServerForkerJar() {
-		return serverForkerJar;
-	}
-
-	@Override
-	public void setPasswordFile(String passwordFile) {
-		this.passwordFile = passwordFile;
-	}
-
-	@Override
-	public String getPasswordFile() {
-		return passwordFile;
-	}
-
-	@Override
-	public void setOperatingLimit(int operatingLimit) {
-		this.operatingLimit = operatingLimit;
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return operatingLimit;
-	}
-
-	@Override
-	public List<URI> getPermittedWorkflowURIs() {
-		String[] pw = this.permittedWorkflows;
-		if (pw == null)
-			return new ArrayList<>();
-		List<URI> uris = new ArrayList<>(pw.length);
-		for (String uri : pw)
-			uris.add(URI.create(uri));
-		return uris;
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(List<URI> permittedWorkflows) {
-		String[] pw = new String[permittedWorkflows.size()];
-		for (int i = 0; i < pw.length; i++)
-			pw[i] = permittedWorkflows.get(i).toString();
-		this.permittedWorkflows = pw;
-	}
-
-	@Override
-	public String getRegistryJar() {
-		return registryJar;
-	}
-
-	@Override
-	public void setRegistryJar(String registryJar) {
-		this.registryJar = registryJar;
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		return generateProvenance > 0;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		this.generateProvenance = (generateProvenance ? 1 : 0);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
deleted file mode 100644
index f361e17..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/StreamLogger.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.taverna.server.master.localworker;
-
-import static java.lang.Thread.interrupted;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-import org.apache.commons.logging.Log;
-
-abstract class StreamLogger {
-	protected final Log log;
-	private Thread t;
-	private InputStream in;
-
-	protected StreamLogger(final String name, InputStream is) {
-		log = getLog("Taverna.Server.LocalWorker." + name);
-		in = is;
-		t = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try (BufferedReader br = new BufferedReader(
-						new InputStreamReader(in))) {
-					String line;
-					while (!interrupted() && (line = br.readLine()) != null)
-						if (!line.isEmpty())
-							write(line);
-				} catch (IOException e) {
-					// Do nothing...
-				} catch (Exception e) {
-					log.warn("failure in reading from " + name, e);
-				}
-			}
-		}, name + ".StreamLogger");
-		t.setContextClassLoader(null);
-		t.setDaemon(true);
-		t.start();
-	}
-
-	/**
-	 * Write a line read from the subprocess to the log.
-	 * <p>
-	 * This needs to be implemented by subclasses in order for the log to be
-	 * correctly written with the class name.
-	 * 
-	 * @param msg
-	 *            The message to write. Guaranteed to have no newline characters
-	 *            in it and to be non-empty.
-	 */
-	protected abstract void write(String msg);
-
-	public void stop() {
-		log.info("trying to close down " + t.getName());
-		t.interrupt();
-		try {
-			in.close();
-		} catch (IOException e) {
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
deleted file mode 100644
index 7139dd7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/localworker/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Implementation of a Taverna Server back-end that works by forking off
- * workflow executors on the local system.
- */
-package org.taverna.server.master.localworker;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
deleted file mode 100644
index 3e27806..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/EmailDispatcher.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification;
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-
-import javax.annotation.PostConstruct;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.mail.MailSender;
-import org.springframework.mail.SimpleMailMessage;
-import org.springframework.mail.javamail.JavaMailSender;
-
-/**
- * How to send a plain text message by email to someone.
- * 
- * @author Donal Fellows
- */
-public class EmailDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "mailto";
-	}
-
-	/**
-	 * @param from
-	 *            Email address that the notification is to come from.
-	 */
-	@Required
-	public void setFrom(String from) {
-		this.from = valid(from, "");
-	}
-
-	/**
-	 * @param host
-	 *            The outgoing SMTP server address.
-	 */
-	@Required
-	public void setSmtpHost(String host) {
-		this.host = valid(host, "");
-	}
-
-	/**
-	 * @param contentType
-	 *            The content type of the message to be sent. For example, "
-	 *            <tt>text/plain</tt>".
-	 */
-	public void setMessageContentType(String contentType) {
-		this.contentType = contentType;
-	}
-
-	/**
-	 * @param sender
-	 *            the sender to set
-	 */
-	public void setSender(MailSender sender) {
-		this.sender = sender;
-	}
-
-	private String from;
-	private String host;
-	private MailSender sender;
-	@SuppressWarnings("unused")
-	private String contentType = TEXT_PLAIN;
-
-	/**
-	 * Try to perform the lookup of the email service. This is called during
-	 * configuration so that any failure happens at a useful, predictable time.
-	 */
-	@PostConstruct
-	public void tryLookup() {
-		if (!isAvailable()) {
-			log.warn("no mail support; disabling email dispatch");
-			sender = null;
-			return;
-		}
-		try {
-			if (sender instanceof JavaMailSender)
-				((JavaMailSender) sender).createMimeMessage();
-		} catch (Throwable t) {
-			log.warn("sender having problems constructing messages; "
-					+ "disabling...", t);
-			sender = null;
-		}
-	}
-
-	@Override
-	public void dispatch(String messageSubject, String messageContent, String to)
-			throws Exception {
-		// Simple checks for acceptability
-		if (!to.matches(".+@.+")) {
-			log.info("did not send email notification: improper email address \""
-					+ to + "\"");
-			return;
-		}
-
-		SimpleMailMessage message = new SimpleMailMessage();
-		message.setFrom(from);
-		message.setTo(to.trim());
-		message.setSubject(messageSubject);
-		message.setText(messageContent);
-		sender.send(message);
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return (host != null && !host.isEmpty() && sender != null
-				&& from != null && !from.isEmpty());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
deleted file mode 100644
index 61640bf..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/JabberDispatcher.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-
-package org.taverna.server.master.notification;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jivesoftware.smack.Chat;
-import org.jivesoftware.smack.ConnectionConfiguration;
-import org.jivesoftware.smack.MessageListener;
-import org.jivesoftware.smack.XMPPConnection;
-import org.jivesoftware.smack.packet.Message;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Send notifications by Jabber/XMPP.
- * 
- * @author Donal Fellows
- */
-public class JabberDispatcher implements MessageDispatcher {
-	@Override
-	public String getName() {
-		return "xmpp";
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private XMPPConnection conn;
-	private String resource = "TavernaServer";
-	private String host = "";
-	private String user = "";
-	private String pass = "";
-
-	/**
-	 * @param resource
-	 *            The XMPP resource to use when connecting the server. This
-	 *            defaults to "<tt>TavernaServer</tt>".
-	 */
-	public void setResource(String resource) {
-		this.resource = resource;
-	}
-
-	/**
-	 * @param service
-	 *            The XMPP service URL.
-	 */
-	public void setHost(String service) {
-		if (service == null || service.trim().isEmpty()
-				|| service.trim().startsWith("$"))
-			this.host = "";
-		else
-			this.host = service.trim();
-	}
-
-	/**
-	 * @param user
-	 *            The user identity to use with the XMPP service.
-	 */
-	public void setUsername(String user) {
-		if (user == null || user.trim().isEmpty()
-				|| user.trim().startsWith("$"))
-			this.user = "";
-		else
-			this.user = user.trim();
-	}
-
-	/**
-	 * @param pass
-	 *            The password to use with the XMPP service.
-	 */
-	public void setPassword(String pass) {
-		if (pass == null || pass.trim().isEmpty()
-				|| pass.trim().startsWith("$"))
-			this.pass = "";
-		else
-			this.pass = pass.trim();
-	}
-
-	@PostConstruct
-	void setup() {
-		try {
-			if (host.isEmpty() || user.isEmpty() || pass.isEmpty()) {
-				log.info("disabling XMPP support; incomplete configuration");
-				conn = null;
-				return;
-			}
-			ConnectionConfiguration cfg = new ConnectionConfiguration(host);
-			cfg.setSendPresence(false);
-			XMPPConnection c = new XMPPConnection(cfg);
-			c.connect();
-			c.login(user, pass, resource);
-			conn = c;
-			log.info("connected to XMPP service <" + host + "> as user <"
-					+ user + ">");
-		} catch (Exception e) {
-			log.info("failed to connect to XMPP server", e);
-		}
-	}
-
-	@PreDestroy
-	public void close() {
-		if (conn != null)
-			conn.disconnect();
-		conn = null;
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return conn != null;
-	}
-
-	@Override
-	public void dispatch(TavernaRun ignored, String messageSubject,
-			String messageContent, String targetParameter) throws Exception {
-		Chat chat = conn.getChatManager().createChat(targetParameter,
-				new DroppingListener());
-		Message m = new Message();
-		m.addBody(null, messageContent);
-		m.setSubject(messageSubject);
-		chat.sendMessage(m);
-	}
-
-	static class DroppingListener implements MessageListener {
-		private Log log = LogFactory
-				.getLog("Taverna.Server.Notification.Jabber");
-
-		@Override
-		public void processMessage(Chat chat, Message message) {
-			if (log.isDebugEnabled())
-				log.debug("unexpectedly received XMPP message from <"
-						+ message.getFrom() + ">; ignoring");
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java b/server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
deleted file mode 100644
index bc0f60d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/NotificationEngine.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A common object for handling dispatch of event-driven messages.
- * 
- * @author Donal Fellows
- */
-public class NotificationEngine {
-	private Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private Map<String, MessageDispatcher> dispatchers;
-	private List<MessageDispatcher> universalDispatchers;
-
-	/**
-	 * @param dispatchers
-	 *            The various dispatchers we want to install.
-	 */
-	@Required
-	public void setDispatchers(List<MessageDispatcher> dispatchers) {
-		this.dispatchers = new HashMap<>();
-		for (MessageDispatcher d : dispatchers)
-			this.dispatchers.put(d.getName(), d);
-	}
-
-	/**
-	 * @param dispatcherList
-	 *            A list of dispatch objects to always dispatch to.
-	 */
-	@Required
-	public void setUniversalDispatchers(List<MessageDispatcher> dispatcherList) {
-		this.universalDispatchers = dispatcherList;
-	}
-
-	private void dispatchToChosenTarget(TavernaRun originator, String scheme,
-			String target, Message message) throws Exception {
-		try {
-			MessageDispatcher d = dispatchers.get(scheme);
-			if (d != null && d.isAvailable())
-				d.dispatch(originator, message.getTitle(scheme),
-						message.getContent(scheme), target);
-			else
-				log.warn("no such notification dispatcher for " + scheme);
-		} catch (URISyntaxException e) {
-			// See if *someone* will handle the message
-			Exception e2 = null;
-			for (MessageDispatcher d : dispatchers.values())
-				try {
-					if (d.isAvailable()) {
-						d.dispatch(originator, message.getTitle(d.getName()),
-								message.getContent(d.getName()), scheme + ":"
-										+ target);
-						return;
-					}
-				} catch (Exception ex) {
-					if (log.isDebugEnabled())
-						log.debug("failed in pseudo-directed dispatch of "
-								+ scheme + ":" + target, ex);
-					e2 = ex;
-				}
-			if (e2 != null)
-				throw e2;
-		}
-	}
-
-	private void dispatchUniversally(TavernaRun originator, Message message)
-			throws Exception {
-		for (MessageDispatcher d : universalDispatchers)
-			try {
-				if (d.isAvailable())
-					d.dispatch(originator, message.getTitle(d.getName()),
-							message.getContent(d.getName()), null);
-			} catch (Exception e) {
-				log.warn("problem in universal dispatcher", e);
-			}
-	}
-
-	/**
-	 * Dispatch a message over the notification fabric.
-	 * 
-	 * @param originator
-	 *            What workflow run was the source of this message?
-	 * @param destination
-	 *            Where the message should get delivered to. The correct format
-	 *            of this is either as a URI of some form (where the scheme
-	 *            determines the dispatcher) or as an invalid URI in which case
-	 *            it is just tried against the possibilities to see if any
-	 *            succeeds.
-	 * @param subject
-	 *            The subject line of the message.
-	 * @param message
-	 *            The plain text body of the message.
-	 * @throws Exception
-	 *             If anything goes wrong with the dispatch process.
-	 */
-	public void dispatchMessage(TavernaRun originator, String destination,
-			Message message) throws Exception {
-		if (destination != null && !destination.trim().isEmpty()) {
-			try {
-				URI toURI = new URI(destination.trim());
-				dispatchToChosenTarget(originator, toURI.getScheme(),
-						toURI.getSchemeSpecificPart(), message);
-			} catch (URISyntaxException e) {
-				// Ignore
-			}
-		}
-		dispatchUniversally(originator, message);
-	}
-
-	/**
-	 * @return The message dispatchers that are actually available (i.e., not
-	 *         disabled by configuration somewhere).
-	 */
-	public List<String> listAvailableDispatchers() {
-		ArrayList<String> result = new ArrayList<>();
-		for (Map.Entry<String, MessageDispatcher> entry : dispatchers
-				.entrySet()) {
-			if (entry.getValue().isAvailable())
-				result.add(entry.getKey());
-		}
-		return result;
-	}
-
-	public interface Message {
-		String getContent(String type);
-
-		String getTitle(String type);
-	}
-}


[26/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/misc/xsd/persistence_1_0.xsd
----------------------------------------------------------------------
diff --git a/server-webapp/src/misc/xsd/persistence_1_0.xsd b/server-webapp/src/misc/xsd/persistence_1_0.xsd
deleted file mode 100644
index a485e30..0000000
--- a/server-webapp/src/misc/xsd/persistence_1_0.xsd
+++ /dev/null
@@ -1,305 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- persistence.xml schema -->
-<xsd:schema targetNamespace="http://java.sun.com/xml/ns/persistence" 
-  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-  xmlns:persistence="http://java.sun.com/xml/ns/persistence"
-  elementFormDefault="qualified" 
-  attributeFormDefault="unqualified" 
-  version="1.0">
-
-  <xsd:annotation>
-    <xsd:documentation>
-      @(#)persistence_1_0.xsd  1.0  Feb 9 2006
-    </xsd:documentation>
-  </xsd:annotation>
-
-  <xsd:annotation>
-    <xsd:documentation>
-
-      DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-
-      Copyright 2005-2007 Sun Microsystems, Inc. All rights reserved.
-
-      The contents of this file are subject to the terms of either the
-      GNU General Public License Version 2 only ("GPL") or the Common
-      Development and Distribution License("CDDL") (collectively, the
-      "License").  You may not use this file except in compliance with
-      the License. You can obtain a copy of the License at
-      https://glassfish.dev.java.net/public/CDDL+GPL.html or
-      glassfish/bootstrap/legal/LICENSE.txt.  See the License for the
-      specific language governing permissions and limitations under the
-      License.
-
-      When distributing the software, include this License Header
-      Notice in each file and include the License file at
-      glassfish/bootstrap/legal/LICENSE.txt.  Sun designates this
-      particular file as subject to the "Classpath" exception as
-      provided by Sun in the GPL Version 2 section of the License file
-      that accompanied this code.  If applicable, add the following
-      below the License Header, with the fields enclosed by brackets []
-      replaced by your own identifying information:
-      "Portions Copyrighted [year] [name of copyright owner]"
-
-      Contributor(s):
-
-      If you wish your version of this file to be governed by only the
-      CDDL or only the GPL Version 2, indicate your decision by adding
-      "[Contributor] elects to include this software in this
-      distribution under the [CDDL or GPL Version 2] license."  If you
-      don't indicate a single choice of license, a recipient has the
-      option to distribute your version of this file under either the
-      CDDL, the GPL Version 2 or to extend the choice of license to its
-      licensees as provided above.  However, if you add GPL Version 2
-      code and therefore, elected the GPL Version 2 license, then the
-      option applies only if the new code is made subject to such
-      option by the copyright holder.
-
-    </xsd:documentation>
-  </xsd:annotation>
-
-   <xsd:annotation>
-     <xsd:documentation><![CDATA[
-
-     This is the XML Schema for the persistence configuration file.
-     The file must be named "META-INF/persistence.xml" in the 
-     persistence archive.
-     Persistence configuration files must indicate
-     the persistence schema by using the persistence namespace:
-
-     http://java.sun.com/xml/ns/persistence
-
-     and indicate the version of the schema by
-     using the version element as shown below:
-
-      <persistence xmlns="http://java.sun.com/xml/ns/persistence"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
-          http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
-        version="1.0">
-          ...
-      </persistence>
-
-    ]]></xsd:documentation>
-  </xsd:annotation>
-
-  <xsd:simpleType name="versionType">
-    <xsd:restriction base="xsd:token">
-      <xsd:pattern value="[0-9]+(\.[0-9]+)*"/>
-    </xsd:restriction>
-  </xsd:simpleType>
-
-  <!-- **************************************************** -->
-
-  <xsd:element name="persistence">
-    <xsd:complexType>
-      <xsd:sequence>
-
-        <!-- **************************************************** -->
-
-        <xsd:element name="persistence-unit" 
-                     minOccurs="0" maxOccurs="unbounded">
-          <xsd:complexType>
-            <xsd:annotation>
-              <xsd:documentation>
-
-                Configuration of a persistence unit.
-
-              </xsd:documentation>
-            </xsd:annotation>
-            <xsd:sequence>
-
-            <!-- **************************************************** -->
-
-              <xsd:element name="description" type="xsd:string" 
-                           minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    Textual description of this persistence unit.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="provider" type="xsd:string" 
-                           minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    Provider class that supplies EntityManagers for this 
-                    persistence unit.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="jta-data-source" type="xsd:string" 
-                           minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    The container-specific name of the JTA datasource to use.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="non-jta-data-source" type="xsd:string" 
-                           minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    The container-specific name of a non-JTA datasource to use.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="mapping-file" type="xsd:string" 
-                           minOccurs="0" maxOccurs="unbounded">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    File containing mapping information. Loaded as a resource 
-                    by the persistence provider.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="jar-file" type="xsd:string" 
-                           minOccurs="0" maxOccurs="unbounded">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    Jar file that should be scanned for entities. 
-                    Not applicable to Java SE persistence units.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="class" type="xsd:string" 
-                           minOccurs="0" maxOccurs="unbounded">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    Class to scan for annotations.  It should be annotated 
-                    with either @Entity, @Embeddable or @MappedSuperclass.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="exclude-unlisted-classes" type="xsd:boolean" 
-                           default="false" minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    When set to true then only listed classes and jars will 
-                    be scanned for persistent classes, otherwise the enclosing 
-                    jar or directory will also be scanned. Not applicable to 
-                    Java SE persistence units.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-              </xsd:element>
-
-              <!-- **************************************************** -->
-
-              <xsd:element name="properties" minOccurs="0">
-                <xsd:annotation>
-                  <xsd:documentation>
-
-                    A list of vendor-specific properties.
-
-                  </xsd:documentation>
-                </xsd:annotation>
-                <xsd:complexType>
-                  <xsd:sequence>
-                    <xsd:element name="property" 
-                                 minOccurs="0" maxOccurs="unbounded">
-                      <xsd:annotation>
-                        <xsd:documentation>
-                          A name-value pair.
-                        </xsd:documentation>
-                      </xsd:annotation>
-                      <xsd:complexType>
-                        <xsd:attribute name="name" type="xsd:string" 
-                                       use="required"/>
-                        <xsd:attribute name="value" type="xsd:string" 
-                                       use="required"/>
-                      </xsd:complexType>
-                    </xsd:element>
-                  </xsd:sequence>
-                </xsd:complexType>
-              </xsd:element>
-
-            </xsd:sequence>
-
-            <!-- **************************************************** -->
-
-            <xsd:attribute name="name" type="xsd:string" use="required">
-              <xsd:annotation>
-                <xsd:documentation>
-
-                  Name used in code to reference this persistence unit.
-
-                </xsd:documentation>
-              </xsd:annotation>
-            </xsd:attribute>
-
-            <!-- **************************************************** -->
-
-            <xsd:attribute name="transaction-type" 
-                           type="persistence:persistence-unit-transaction-type">
-              <xsd:annotation>
-                <xsd:documentation>
-
-                  Type of transactions used by EntityManagers from this 
-                  persistence unit.
-
-                </xsd:documentation>
-              </xsd:annotation>
-            </xsd:attribute>
-
-          </xsd:complexType>
-        </xsd:element>
-      </xsd:sequence>
-      <xsd:attribute name="version" type="persistence:versionType" 
-                     fixed="1.0" use="required"/>
-    </xsd:complexType>
-  </xsd:element>
-
-  <!-- **************************************************** -->
-
-  <xsd:simpleType name="persistence-unit-transaction-type">
-    <xsd:annotation>
-      <xsd:documentation>
-
-        public enum TransactionType { JTA, RESOURCE_LOCAL };
-
-      </xsd:documentation>
-    </xsd:annotation>
-    <xsd:restriction base="xsd:token">
-      <xsd:enumeration value="JTA"/>
-      <xsd:enumeration value="RESOURCE_LOCAL"/>
-    </xsd:restriction>
-  </xsd:simpleType>
-
-</xsd:schema>
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java b/server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
deleted file mode 100644
index 79c026b..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Arrays;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.master.admin.Admin;
-import org.taverna.server.master.common.Credential.KeyPair;
-import org.taverna.server.master.common.Credential.Password;
-import org.taverna.server.master.common.Capability;
-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.Uri;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc;
-import org.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
-import org.taverna.server.master.rest.TavernaServerListenersREST.Properties;
-import org.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
-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.CapabilityList;
-import org.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
-import org.taverna.server.master.rest.TavernaServerREST.RunList;
-import org.taverna.server.master.rest.TavernaServerREST.ServerDescription;
-import org.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
-import org.taverna.server.master.soap.DirEntry;
-import org.taverna.server.master.soap.FileContents;
-import org.taverna.server.master.soap.PermissionList;
-
-/**
- * This test file ensures that the JAXB bindings will work once deployed instead
- * of mysteriously failing in service.
- * 
- * @author Donal Fellows
- */
-public class JaxbSanityTest {
-	SchemaOutputResolver sink;
-	StringWriter schema;
-
-	String schema() {
-		return schema.toString();
-	}
-
-	@Before
-	public void init() {
-		schema = new StringWriter();
-		sink = new SchemaOutputResolver() {
-			@Override
-			public Result createOutput(String namespaceUri,
-					String suggestedFileName) throws IOException {
-				StreamResult sr = new StreamResult(schema);
-				sr.setSystemId("/dev/null");
-				return sr;
-			}
-		};
-		assertEquals("", schema());
-	}
-
-	private boolean printSchema = false;
-
-	private void testJAXB(Class<?>... classes) throws Exception {
-		JAXBContext.newInstance(classes).generateSchema(sink);
-		if (printSchema)
-			System.out.println(schema());
-		assertTrue(schema().length() > 0);
-	}
-
-	@Test
-	public void testJAXBForDirEntryReference() throws Exception {
-		JAXBContext.newInstance(DirEntryReference.class).generateSchema(sink);
-		assertTrue(schema().length() > 0);
-	}
-
-	@Test
-	public void testJAXBForInputDescription() throws Exception {
-		testJAXB(InputDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunReference() throws Exception {
-		testJAXB(RunReference.class);
-	}
-
-	@Test
-	public void testJAXBForWorkflow() throws Exception {
-		testJAXB(Workflow.class);
-	}
-
-	@Test
-	public void testJAXBForStatus() throws Exception {
-		testJAXB(Status.class);
-	}
-
-	@Test
-	public void testJAXBForUri() throws Exception {
-		testJAXB(Uri.class);
-	}
-
-	@Test
-	public void testJAXBForDirectoryContents() throws Exception {
-		testJAXB(DirectoryContents.class);
-	}
-
-	@Test
-	public void testJAXBForListenerDefinition() throws Exception {
-		testJAXB(ListenerDefinition.class);
-	}
-
-	@Test
-	public void testJAXBForMakeOrUpdateDirEntry() throws Exception {
-		testJAXB(MakeOrUpdateDirEntry.class);
-	}
-
-	@Test
-	public void testJAXBForInDesc() throws Exception {
-		testJAXB(InDesc.class);
-	}
-
-	@Test
-	public void testJAXBForInputsDescriptor() throws Exception {
-		testJAXB(InputsDescriptor.class);
-	}
-
-	@Test
-	public void testJAXBForListenerDescription() throws Exception {
-		testJAXB(ListenerDescription.class);
-	}
-
-	@Test
-	public void testJAXBForListeners() throws Exception {
-		testJAXB(Listeners.class);
-	}
-
-	@Test
-	public void testJAXBForProperties() throws Exception {
-		testJAXB(Properties.class);
-	}
-
-	@Test
-	public void testJAXBForPropertyDescription() throws Exception {
-		testJAXB(PropertyDescription.class);
-	}
-
-	@Test
-	public void testJAXBForPermittedListeners() throws Exception {
-		testJAXB(PermittedListeners.class);
-	}
-
-	@Test
-	public void testJAXBForPermittedWorkflows() throws Exception {
-		testJAXB(PermittedWorkflows.class);
-	}
-
-	@Test
-	public void testJAXBForEnabledNotifiers() throws Exception {
-		testJAXB(EnabledNotificationFabrics.class);
-	}
-
-	@Test
-	public void testJAXBForServerDescription() throws Exception {
-		testJAXB(ServerDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunDescription() throws Exception {
-		testJAXB(RunDescription.class);
-	}
-
-	@Test
-	public void testJAXBForRunList() throws Exception {
-		testJAXB(RunList.class);
-	}
-
-	@Test
-	public void testJAXBForPolicyDescription() throws Exception {
-		testJAXB(PolicyDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityCredential() throws Exception {
-		testJAXB(CredentialHolder.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityCredentialList() throws Exception {
-		testJAXB(TavernaServerSecurityREST.CredentialList.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityTrust() throws Exception {
-		testJAXB(Trust.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityTrustList() throws Exception {
-		testJAXB(TavernaServerSecurityREST.TrustList.class);
-	}
-
-	@Test
-	public void testJAXBForPermission() throws Exception {
-		testJAXB(Permission.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityPermissionDescription() throws Exception {
-		testJAXB(TavernaServerSecurityREST.PermissionDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityPermissionsDescription() throws Exception {
-		testJAXB(TavernaServerSecurityREST.PermissionsDescription.class);
-	}
-
-	@Test
-	public void testJAXBForSecurityDescriptor() throws Exception {
-		testJAXB(TavernaServerSecurityREST.Descriptor.class);
-	}
-
-	@Test
-	public void testJAXBForProfileList() throws Exception {
-		testJAXB(ProfileList.class);
-	}
-
-	@Test
-	public void testJAXBForDirEntry() throws Exception {
-		testJAXB(DirEntry.class);
-	}
-
-	@Test
-	public void testJAXBForCapability() throws Exception {
-		testJAXB(Capability.class);
-	}
-
-	@Test
-	public void testJAXBForCapabilityList() throws Exception {
-		testJAXB(CapabilityList.class);
-	}
-
-	@Test
-	public void testJAXBForEverythingREST() throws Exception {
-		testJAXB(DirEntryReference.class, InputDescription.class,
-				RunReference.class, Workflow.class, Status.class,
-				DirectoryContents.class, InDesc.class,
-				ListenerDefinition.class, MakeOrUpdateDirEntry.class,
-				InputsDescriptor.class, ListenerDescription.class,
-				Listeners.class, Properties.class, PropertyDescription.class,
-				PermittedListeners.class, PermittedWorkflows.class,
-				EnabledNotificationFabrics.class, ServerDescription.class,
-				RunDescription.class, Uri.class, RunList.class,
-				PolicyDescription.class, CredentialHolder.class, Trust.class,
-				TavernaServerSecurityREST.CredentialList.class,
-				TavernaServerSecurityREST.TrustList.class, Permission.class,
-				TavernaServerSecurityREST.Descriptor.class,
-				TavernaServerSecurityREST.PermissionDescription.class,
-				TavernaServerSecurityREST.PermissionsDescription.class,
-				ProfileList.class, Capability.class, CapabilityList.class);
-	}
-
-	@Test
-	public void testJAXBForEverythingSOAP() throws Exception {
-		testJAXB(DirEntry.class, FileContents.class, InputDescription.class,
-				Permission.class, PermissionList.class,
-				PermissionList.SinglePermissionMapping.class,
-				RunReference.class, Status.class, Trust.class, Uri.class,
-				ProfileList.class, Workflow.class, Capability.class);
-	}
-
-	@Test
-	public void testUserPassSerializeDeserialize() throws Exception {
-		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
-
-		Password password = new Password();
-		password.username = "foo";
-		password.password = "bar";
-
-		// Serialize
-		StringWriter sw = new StringWriter();
-		CredentialHolder credIn = new CredentialHolder(password);
-		c.createMarshaller().marshal(credIn, sw);
-
-		// Deserialize
-		StringReader sr = new StringReader(sw.toString());
-		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
-
-		// Test value-equivalence
-		assertEquals(credIn.getClass(), credOutObj.getClass());
-		CredentialHolder credOut = (CredentialHolder) credOutObj;
-		assertEquals(credIn.credential.getClass(),
-				credOut.credential.getClass());
-		assertEquals(credIn.getUserpass().username,
-				credOut.getUserpass().username);
-		assertEquals(credIn.getUserpass().password,
-				credOut.getUserpass().password);
-	}
-
-	@Test
-	public void testKeypairSerializeDeserialize() throws Exception {
-		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
-
-		KeyPair keypair = new KeyPair();
-		keypair.credentialName = "foo";
-		keypair.credentialBytes = new byte[] { 1, 2, 3 };
-
-		// Serialize
-		StringWriter sw = new StringWriter();
-		CredentialHolder credIn = new CredentialHolder(keypair);
-		c.createMarshaller().marshal(credIn, sw);
-
-		// Deserialize
-		StringReader sr = new StringReader(sw.toString());
-		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
-
-		// Test value-equivalence
-		assertEquals(credIn.getClass(), credOutObj.getClass());
-		CredentialHolder credOut = (CredentialHolder) credOutObj;
-		assertEquals(credIn.credential.getClass(),
-				credOut.credential.getClass());
-		assertEquals(credIn.getKeypair().credentialName,
-				credOut.getKeypair().credentialName);
-		assertTrue(Arrays.equals(credIn.getKeypair().credentialBytes,
-				credOut.getKeypair().credentialBytes));
-	}
-
-	@Test
-	public void testJAXBforAdmininstration() throws Exception {
-		testJAXB(Admin.AdminDescription.class);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java b/server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
deleted file mode 100644
index 9665cf0..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
+++ /dev/null
@@ -1,246 +0,0 @@
-package org.taverna.server.master;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonMap;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.common.RunReference;
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-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.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.mocks.ExampleRun;
-import org.taverna.server.master.mocks.MockPolicy;
-import org.taverna.server.master.mocks.SimpleListenerFactory;
-import org.taverna.server.master.mocks.SimpleNonpersistentRunStore;
-
-public class TavernaServerImplTest {
-	private TavernaServer server;
-	private MockPolicy policy;
-	private SimpleNonpersistentRunStore store;
-	@java.lang.SuppressWarnings("unused")
-	private ExampleRun.Builder runFactory;
-	private SimpleListenerFactory lFactory;
-	private TavernaServerSupport support;
-
-	private String lrunname;
-	private String lrunconf;
-
-	Listener makeListener(TavernaRun run, final String config) {
-		lrunname = run.toString();
-		lrunconf = config;
-		return new Listener() {
-			@Override
-			public String getConfiguration() {
-				return config;
-			}
-
-			@Override
-			public String getName() {
-				return "bar";
-			}
-
-			@Override
-			public String getProperty(String propName)
-					throws NoListenerException {
-				throw new NoListenerException();
-			}
-
-			@Override
-			public String getType() {
-				return "foo";
-			}
-
-			@Override
-			public String[] listProperties() {
-				return new String[0];
-			}
-
-			@Override
-			public void setProperty(String propName, String value)
-					throws NoListenerException, BadPropertyValueException {
-				throw new NoListenerException();
-			}
-		};
-	}
-
-	@Before
-	public void wireup() throws Exception {
-		// Wire everything up; ought to be done with Spring, but this works...
-		server = new TavernaServer() {
-			@Override
-			protected RunREST makeRunInterface() {
-				return new RunREST() {
-					@Override
-					protected ListenersREST makeListenersInterface() {
-						return new ListenersREST() {
-							@Override
-							protected SingleListenerREST makeListenerInterface() {
-								return new SingleListenerREST() {
-									@Override
-									protected ListenerPropertyREST makePropertyInterface() {
-										return new ListenerPropertyREST() {
-										};
-									}
-								};
-							}
-						};
-					}
-
-					@Override
-					protected RunSecurityREST makeSecurityInterface() {
-						return new RunSecurityREST() {
-						};
-					}
-
-					@Override
-					protected DirectoryREST makeDirectoryInterface() {
-						return new DirectoryREST() {
-						};
-					}
-
-					@Override
-					protected InputREST makeInputInterface() {
-						return new InputREST() {
-						};
-					}
-
-					@Override
-					protected InteractionFeed makeInteractionFeed() {
-						return null; // TODO...
-					}
-				};
-			}
-
-			@Override
-			public PolicyView getPolicyDescription() {
-				return new PolicyREST();
-			}
-		};
-		support = new TavernaServerSupport();
-		server.setSupport(support);
-		support.setWebapp(server);
-		support.setLogGetPrincipalFailures(false);
-		support.setStateModel(new ManagementModel() {
-			@Override
-			public boolean getAllowNewWorkflowRuns() {
-				return true;
-			}
-
-			@Override
-			public boolean getLogIncomingWorkflows() {
-				return false;
-			}
-
-			@Override
-			public boolean getLogOutgoingExceptions() {
-				return false;
-			}
-
-			@Override
-			public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-			}
-
-			@Override
-			public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-			}
-
-			@Override
-			public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-			}
-
-			@Override
-			public String getUsageRecordLogFile() {
-				return null;
-			}
-
-			@Override
-			public void setUsageRecordLogFile(String usageRecordLogFile) {
-			}
-		});
-		server.setPolicy(policy = new MockPolicy());
-		support.setPolicy(policy);
-		server.setRunStore(store = new SimpleNonpersistentRunStore());
-		support.setRunStore(store);
-		store.setPolicy(policy);
-		support.setRunFactory(runFactory = new ExampleRun.Builder(1));
-		support.setListenerFactory(lFactory = new SimpleListenerFactory());
-		lFactory.setBuilders(singletonMap(
-				"foo",
-				(SimpleListenerFactory.Builder) new SimpleListenerFactory.Builder() {
-					@Override
-					public Listener build(TavernaRun run, String configuration)
-							throws NoListenerException {
-						return makeListener(run, configuration);
-					}
-				}));
-	}
-
-	@Test
-	public void defaults1() {
-		assertNotNull(server);
-	}
-
-	@Test
-	public void defaults2() {
-		assertEquals(10, server.getServerMaxRuns());
-	}
-
-	@Test
-	public void defaults3() {
-		assertEquals(1, server.getServerListeners().length);
-	}
-
-	@Test
-	public void defaults4() {
-		assertNotNull(support.getPrincipal());
-	}
-
-	@Test
-	public void serverAsksPolicyForMaxRuns() {
-		int oldmax = policy.maxruns;
-		try {
-			policy.maxruns = 1;
-			assertEquals(1, server.getServerMaxRuns());
-		} finally {
-			policy.maxruns = oldmax;
-		}
-	}
-
-	@Test
-	public void makeAndKillARun() throws NoUpdateException, UnknownRunException {
-		RunReference rr = server.submitWorkflow(null);
-		assertNotNull(rr);
-		assertNotNull(rr.name);
-		server.destroyRun(rr.name);
-	}
-
-	@Test
-	public void makeListenKillRun() throws Exception {
-		RunReference run = server.submitWorkflow(null);
-		try {
-			lrunname = lrunconf = null;
-			assertEquals(asList("foo"), asList(server.getServerListeners()));
-			String l = server.addRunListener(run.name, "foo", "foobar");
-			assertEquals("bar", l);
-			assertEquals("foobar", lrunconf);
-			assertEquals(lrunname, support.getRun(run.name).toString());
-			assertEquals(asList("default", "bar"),
-					asList(server.getRunListeners(run.name)));
-			assertEquals(0,
-					server.getRunListenerProperties(run.name, "bar").length);
-		} finally {
-			try {
-				server.destroyRun(run.name);
-			} catch (Exception e) {
-				// Ignore
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java b/server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
deleted file mode 100644
index 0450317..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.taverna.server.master;
-
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.taverna.server.master.common.Workflow;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-public class WorkflowSerializationTest {
-	@Test
-	public void testWorkflowSerialization()
-			throws ParserConfigurationException, IOException,
-			ClassNotFoundException {
-		DocumentBuilder db = DocumentBuilderFactory.newInstance()
-				.newDocumentBuilder();
-		Document doc = db.getDOMImplementation().createDocument(null, null,
-				null);
-		Element workflow = doc.createElementNS(T2FLOW_NS, T2FLOW_ROOTNAME);
-		Element foo = doc.createElementNS("urn:foo:bar", "pqr:foo");
-		foo.setTextContent("bar");
-		foo.setAttribute("xyz", "abc");
-		workflow.appendChild(foo);
-		Workflow w = new Workflow(workflow);
-
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
-			oos.writeObject(w);
-		}
-
-		Object o;
-		try (ObjectInputStream ois = new ObjectInputStream(
-				new ByteArrayInputStream(baos.toByteArray()))) {
-			o = ois.readObject();
-		}
-
-		Assert.assertNotNull(o);
-		Assert.assertEquals(w.getClass(), o.getClass());
-		Workflow w2 = (Workflow) o;
-		Assert.assertNotNull(w2.getT2flowWorkflow());
-		Element e = w2.getT2flowWorkflow();
-		Assert.assertEquals(T2FLOW_ROOTNAME, e.getLocalName());
-		Assert.assertEquals(T2FLOW_NS, e.getNamespaceURI());
-		e = (Element) e.getFirstChild();
-		Assert.assertEquals("foo", e.getLocalName());
-		Assert.assertEquals("pqr", e.getPrefix());
-		Assert.assertEquals("urn:foo:bar", e.getNamespaceURI());
-		Assert.assertEquals("bar", e.getTextContent());
-		Assert.assertEquals(1, e.getChildNodes().getLength());
-		// WARNING: These are dependent on how namespaces are encoded!
-		Assert.assertEquals(2, e.getAttributes().getLength());
-		Assert.assertEquals("xyz", ((Attr) e.getAttributes().item(1)).getLocalName());
-		Assert.assertEquals("abc", e.getAttribute("xyz"));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java b/server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
deleted file mode 100644
index a2a0791..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.mocks;
-
-import static java.util.Calendar.MINUTE;
-import static java.util.Collections.unmodifiableList;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.common.Status.Initialized;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.ws.rs.core.HttpHeaders;
-import javax.xml.ws.handler.MessageContext;
-
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.master.common.Credential;
-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.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-import org.taverna.server.master.factories.RunFactory;
-import org.taverna.server.master.interfaces.Directory;
-import org.taverna.server.master.interfaces.Input;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-@SuppressWarnings("serial")
-public class ExampleRun implements TavernaRun, TavernaSecurityContext {
-	String id;
-	List<Listener> listeners;
-	Workflow workflow;
-	Status status;
-	Date expiry;
-	UsernamePrincipal owner;
-	String inputBaclava;
-	String outputBaclava;
-	java.io.File realRoot;
-	List<Input> inputs;
-	String name;
-
-	public ExampleRun(UsernamePrincipal creator, Workflow workflow, Date expiry) {
-		this.id = randomUUID().toString();
-		this.listeners = new ArrayList<>();
-		this.status = Initialized;
-		this.owner = creator;
-		this.workflow = workflow;
-		this.expiry = expiry;
-		this.inputs = new ArrayList<>();
-		listeners.add(new DefaultListener());
-	}
-
-	@Override
-	public void addListener(Listener l) {
-		listeners.add(l);
-	}
-
-	@Override
-	public void destroy() {
-		// This does nothing...
-	}
-
-	@Override
-	public Date getExpiry() {
-		return expiry;
-	}
-
-	@Override
-	public List<Listener> getListeners() {
-		return listeners;
-	}
-
-	@Override
-	public TavernaSecurityContext getSecurityContext() {
-		return this;
-	}
-
-	@Override
-	public Status getStatus() {
-		return status;
-	}
-
-	@Override
-	public Workflow getWorkflow() {
-		return workflow;
-	}
-
-	@Override
-	public Directory getWorkingDirectory() {
-		// LATER: Implement this!
-		throw new UnsupportedOperationException("not yet implemented");
-	}
-
-	@Override
-	public void setExpiry(Date d) {
-		if (d.after(new Date()))
-			this.expiry = d;
-	}
-
-	@Override
-	public String setStatus(Status s) {
-		this.status = s;
-		return null;
-	}
-
-	@Override
-	public UsernamePrincipal getOwner() {
-		return owner;
-	}
-
-	public static class Builder implements RunFactory {
-		private int lifetime;
-
-		public Builder(int initialLifetimeMinutes) {
-			this.lifetime = initialLifetimeMinutes;
-		}
-
-		@Override
-		public TavernaRun create(UsernamePrincipal creator, Workflow workflow) {
-			Calendar c = GregorianCalendar.getInstance();
-			c.add(MINUTE, lifetime);
-			return new ExampleRun(creator, workflow, c.getTime());
-		}
-
-		@Override
-		public boolean isAllowingRunsToStart() {
-			return true;
-		}
-	}
-
-	static final String[] emptyArray = new String[0];
-
-	class DefaultListener implements Listener {
-		@Override
-		public String getConfiguration() {
-			return "";
-		}
-
-		@Override
-		public String getName() {
-			return "default";
-		}
-
-		@Override
-		public String getType() {
-			return "default";
-		}
-
-		@Override
-		public String[] listProperties() {
-			return emptyArray;
-		}
-
-		@Override
-		public String getProperty(String propName) throws NoListenerException {
-			throw new NoListenerException("no such property");
-		}
-
-		@Override
-		public void setProperty(String propName, String value)
-				throws NoListenerException {
-			throw new NoListenerException("no such property");
-		}
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		return inputBaclava;
-	}
-
-	@Override
-	public List<Input> getInputs() {
-		return unmodifiableList(inputs);
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		return outputBaclava;
-	}
-
-	class ExampleInput implements Input {
-		public String name;
-		public String file;
-		public String value;
-		public String delim;
-
-		public ExampleInput(String name) {
-			this.name = name;
-		}
-
-		@Override
-		public String getFile() {
-			return file;
-		}
-
-		@Override
-		public String getName() {
-			return name;
-		}
-
-		@Override
-		public String getValue() {
-			return value;
-		}
-
-		@Override
-		public void setFile(String file) throws FilesystemAccessException,
-				BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			checkBadFilename(file);
-			this.file = file;
-			this.value = null;
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setValue(String value) throws BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			this.value = value;
-			this.file = null;
-			inputBaclava = null;
-		}
-
-		void reset() {
-			this.file = null;
-			this.value = null;
-		}
-
-		@Override
-		public String getDelimiter() {
-			return delim;
-		}
-
-		@Override
-		public void setDelimiter(String delimiter)
-				throws BadStateChangeException {
-			if (status != Status.Initialized)
-				throw new BadStateChangeException();
-			if (delimiter == null)
-				delim = null;
-			else
-				delim = delimiter.substring(0, 1);
-		}
-	}
-
-	@Override
-	public Input makeInput(String name) throws BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		Input i = new ExampleInput(name);
-		inputs.add(i);
-		return i;
-	}
-
-	static void checkBadFilename(String filename)
-			throws FilesystemAccessException {
-		if (filename.startsWith("/"))
-			throw new FilesystemAccessException("filename may not be absolute");
-		if (Arrays.asList(filename.split("/")).contains(".."))
-			throw new FilesystemAccessException(
-					"filename may not refer to parent");
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		checkBadFilename(filename);
-		inputBaclava = filename;
-		for (Input i : inputs)
-			((ExampleInput) i).reset();
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		if (status != Status.Initialized)
-			throw new BadStateChangeException();
-		if (filename != null)
-			checkBadFilename(filename);
-		outputBaclava = filename;
-	}
-
-	private Date created = new Date();
-	@Override
-	public Date getCreationTimestamp() {
-		return created;
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		return null;
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		return null;
-	}
-
-	@Override
-	public Credential[] getCredentials() {
-		return new Credential[0];
-	}
-
-	@Override
-	public void addCredential(Credential toAdd) {
-	}
-
-	@Override
-	public void deleteCredential(Credential toDelete) {
-	}
-
-	@Override
-	public Trust[] getTrusted() {
-		return new Trust[0];
-	}
-
-	@Override
-	public void addTrusted(Trust toAdd) {
-	}
-
-	@Override
-	public void deleteTrusted(Trust toDelete) {
-	}
-
-	@Override
-	public void validateCredential(Credential c)
-			throws InvalidCredentialException {
-	}
-
-	@Override
-	public void validateTrusted(Trust t) throws InvalidCredentialException {
-	}
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// Do nothing
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders headers) {
-		// Do nothing
-	}
-
-	@Override
-	public void conveySecurity() throws GeneralSecurityException, IOException {
-		// Do nothing
-	}
-
-	@Override
-	public SecurityContextFactory getFactory() {
-		return null;
-	}
-
-	private Set<String> destroyers = new HashSet<String>();
-	private Set<String> updaters = new HashSet<String>();
-	private Set<String> readers = new HashSet<String>();
-	@Override
-	public Set<String> getPermittedDestroyers() {
-		return destroyers;
-	}
-
-	@Override
-	public void setPermittedDestroyers(Set<String> destroyers) {
-		this.destroyers = destroyers;
-		updaters.addAll(destroyers);
-		readers.addAll(destroyers);
-	}
-
-	@Override
-	public Set<String> getPermittedUpdaters() {
-		return updaters;
-	}
-
-	@Override
-	public void setPermittedUpdaters(Set<String> updaters) {
-		this.updaters = updaters;
-		this.updaters.addAll(destroyers);
-		readers.addAll(updaters);
-	}
-
-	@Override
-	public Set<String> getPermittedReaders() {
-		return readers;
-	}
-
-	@Override
-	public void setPermittedReaders(Set<String> readers) {
-		this.readers = readers;
-		this.readers.addAll(destroyers);
-		this.readers.addAll(updaters);
-	}
-
-	@Override
-	public String getId() {
-		return id;
-	}
-
-	@Override
-	public void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception {
-		// Do nothing
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public void setName(String name) {
-		this.name = (name.length() > 5 ? name.substring(0, 5) : name);
-	}
-
-	@Override
-	public void ping() throws UnknownRunException {
-		// Do nothing
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		// TODO Auto-generated method stub
-		
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java b/server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
deleted file mode 100644
index 81dd08c..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.taverna.server.master.mocks;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-public class MockPolicy extends SimpleServerPolicy {
-	public MockPolicy() {
-		super();
-		super.setCleanerInterval(30);
-	}
-
-	public int maxruns = 10;
-	Integer usermaxruns;
-	Set<TavernaRun> denyaccess = new HashSet<>();
-	boolean exnOnUpdate, exnOnCreate, exnOnDelete;
-
-	@Override
-	public int getMaxRuns() {
-		return maxruns;
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal user) {
-		return usermaxruns;
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
-		return !denyaccess.contains(run);
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal user, Workflow workflow)
-			throws NoCreateException {
-		if (this.exnOnCreate)
-			throw new NoCreateException();
-	}
-
-	@Override
-	public void permitDestroy(UsernamePrincipal user, TavernaRun run)
-			throws NoDestroyException {
-		if (this.exnOnDelete)
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
-			throws NoUpdateException {
-		if (this.exnOnUpdate)
-			throw new NoUpdateException();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java b/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
deleted file mode 100644
index d864214..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.taverna.server.master.mocks;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.factories.ListenerFactory;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * A factory for event listener. The factory is configured using Spring.
- * 
- * @author Donal Fellows
- */
-public class SimpleListenerFactory implements ListenerFactory {
-	private Map<String, Builder> builders = new HashMap<>();
-
-	public void setBuilders(Map<String, Builder> builders) {
-		this.builders = builders;
-	}
-
-	@Override
-	public List<String> getSupportedListenerTypes() {
-		return new ArrayList<>(builders.keySet());
-	}
-
-	@Override
-	public Listener makeListener(TavernaRun run, String listenerType,
-			String configuration) throws NoListenerException {
-		Builder b = builders.get(listenerType);
-		if (b == null)
-			throw new NoListenerException("no such listener type");
-		Listener l = b.build(run, configuration);
-		run.addListener(l);
-		return l;
-	}
-
-	/**
-	 * How to actually construct a listener.
-	 * 
-	 * @author Donal Fellows
-	 */
-	public interface Builder {
-		/**
-		 * Make an event listener attached to a run.
-		 * 
-		 * @param run
-		 *            The run to attach to.
-		 * @param configuration
-		 *            A user-specified configuration document. The constructed
-		 *            listener <i>should</i> process this configuration document
-		 *            and be able to return it to the user when requested.
-		 * @return The listener object.
-		 * @throws NoListenerException
-		 *             If the listener construction failed or the
-		 *             <b>configuration</b> document was bad in some way.
-		 */
-		public Listener build(TavernaRun run, String configuration)
-				throws NoListenerException;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
deleted file mode 100644
index a3751e4..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.taverna.server.master.mocks;
-
-import java.lang.ref.WeakReference;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-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.utils.UsernamePrincipal;
-
-/**
- * Example of a store for Taverna Workflow Runs.
- * 
- * @author Donal Fellows
- */
-public class SimpleNonpersistentRunStore implements RunStore {
-	private Map<String, TavernaRun> store = new HashMap<>();
-	private Object lock = new Object();
-
-	Timer timer;
-	private CleanerTask cleaner;
-
-	/**
-	 * The connection to the main policy store. Suitable for wiring up with
-	 * Spring.
-	 * 
-	 * @param p
-	 *            The policy to connect to.
-	 */
-	public void setPolicy(SimpleServerPolicy p) {
-		p.store = this;
-		cleanerIntervalUpdated(p.getCleanerInterval());
-	}
-
-	public SimpleNonpersistentRunStore() {
-		timer = new Timer("SimpleNonpersistentRunStore.CleanerTimer", true);
-		cleanerIntervalUpdated(300);
-	}
-
-	@Override
-	protected void finalize() {
-		timer.cancel();
-	}
-
-	/**
-	 * Remove and destroy all runs that are expired at the moment that this
-	 * method starts.
-	 */
-	void clean() {
-		Date now = new Date();
-		synchronized (lock) {
-			// Use an iterator so we have access to its remove() method...
-			Iterator<TavernaRun> i = store.values().iterator();
-			while (i.hasNext()) {
-				TavernaRun w = i.next();
-				if (w.getExpiry().before(now)) {
-					i.remove();
-					try {
-						w.destroy();
-					} catch (NoDestroyException e) {
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Reconfigure the cleaner task's call interval. This is called internally
-	 * and from the Policy when the interval is set there.
-	 * 
-	 * @param intervalInSeconds
-	 *            How long between runs of the cleaner task, in seconds.
-	 */
-	void cleanerIntervalUpdated(int intervalInSeconds) {
-		if (cleaner != null)
-			cleaner.cancel();
-		cleaner = new CleanerTask(this, intervalInSeconds);
-	}
-
-	@Override
-	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException {
-		synchronized (lock) {
-			TavernaRun w = store.get(uuid);
-			if (w == null || !p.permitAccess(user, w))
-				throw new UnknownRunException();
-			return w;
-		}
-	}
-
-	@Override
-	public TavernaRun getRun(String uuid) throws UnknownRunException {
-		synchronized (lock) {
-			TavernaRun w = store.get(uuid);
-			if (w == null)
-				throw new UnknownRunException();
-			return w;
-		}
-	}
-
-	@Override
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		Map<String, TavernaRun> filtered = new HashMap<>();
-		synchronized (lock) {
-			for (Map.Entry<String, TavernaRun> entry : store.entrySet())
-				if (p.permitAccess(user, entry.getValue()))
-					filtered.put(entry.getKey(), entry.getValue());
-		}
-		return filtered;
-	}
-
-	@Override
-	public String registerRun(TavernaRun run) {
-		synchronized (lock) {
-			store.put(run.getId(), run);
-			return run.getId();
-		}
-	}
-
-	@Override
-	public void unregisterRun(String uuid) {
-		synchronized (lock) {
-			store.remove(uuid);
-		}
-	}
-}
-
-class CleanerTask extends TimerTask {
-	WeakReference<SimpleNonpersistentRunStore> store;
-
-	CleanerTask(SimpleNonpersistentRunStore store, int interval) {
-		this.store = new WeakReference<>(store);
-		int tms = interval * 1000;
-		store.timer.scheduleAtFixedRate(this, tms, tms);
-	}
-
-	@Override
-	public void run() {
-		SimpleNonpersistentRunStore s = store.get();
-		if (s != null) {
-			s.clean();
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java b/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
deleted file mode 100644
index 1a68d2c..0000000
--- a/server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package org.taverna.server.master.mocks;
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.NoCreateException;
-import org.taverna.server.master.exceptions.NoDestroyException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * A very simple (and unsafe) security model. The number of runs is configurable
- * through Spring (or 10 if unconfigured) with no per-user limits supported, all
- * workflows are permitted, and all identified users may create a workflow run.
- * Any user may read off information about any run, but only its owner may
- * modify or destroy it.
- * <p>
- * Note that this is a <i>Policy Enforcement Point</i> for access control to
- * individual workflows.
- * 
- * @author Donal Fellows
- */
-public class SimpleServerPolicy implements Policy {
-	private int maxRuns = 10;
-	private int cleanerInterval;
-	SimpleNonpersistentRunStore store;
-
-	public void setMaxRuns(int maxRuns) {
-		this.maxRuns = maxRuns;
-	}
-
-	@Override
-	public int getMaxRuns() {
-		return maxRuns;
-	}
-
-	@Override
-	public Integer getMaxRuns(UsernamePrincipal p) {
-		return null; // No per-user limits
-	}
-
-	public int getCleanerInterval() {
-		return cleanerInterval;
-	}
-
-	/**
-	 * Sets how often the store of workflow runs will try to clean out expired
-	 * runs.
-	 * 
-	 * @param intervalInSeconds
-	 */
-	public void setCleanerInterval(int intervalInSeconds) {
-		cleanerInterval = intervalInSeconds;
-		if (store != null)
-			store.cleanerIntervalUpdated(intervalInSeconds);
-	}
-
-	@Override
-	public boolean permitAccess(UsernamePrincipal p, TavernaRun run) {
-		// No secrets here!
-		return true;
-	}
-
-	@Override
-	public void permitCreate(UsernamePrincipal p, Workflow workflow)
-			throws NoCreateException {
-		// Only identified users may create
-		if (p == null)
-			throw new NoCreateException();
-		// Global run count limit enforcement
-		if (store.listRuns(p, this).size() >= maxRuns)
-			throw new NoCreateException();
-		// Per-user run count enforcement would come here
-	}
-
-	@Override
-	public void permitDestroy(UsernamePrincipal p, TavernaRun run)
-			throws NoDestroyException {
-		// Only the creator may destroy
-		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
-			throw new NoDestroyException();
-	}
-
-	@Override
-	public void permitUpdate(UsernamePrincipal p, TavernaRun run)
-			throws NoUpdateException {
-		// Only the creator may change
-		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
-			throw new NoUpdateException();
-	}
-
-	@Override
-	public int getOperatingLimit() {
-		return 1;
-	}
-
-	@Override
-	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
-		return null;
-	}
-
-	@Override
-	public void setPermittedWorkflowURIs(UsernamePrincipal user,
-			List<URI> permitted) {
-		// Ignore
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/resources/example.xml
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/resources/example.xml b/server-webapp/src/test/resources/example.xml
deleted file mode 100644
index 14cc242..0000000
--- a/server-webapp/src/test/resources/example.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
-
-	<bean id="policy" class="org.taverna.server.master.mocks.SimpleServerPolicy"
-		lazy-init="false" scope="singleton">
-		<property name="maxRuns" value="1">
-			<description>
-				Limit on total number of simultaneous runs.
-			</description>
-		</property>
-		<property name="cleanerInterval" value="300">
-			<description>
-				Time between trying to delete expired runs, in seconds.
-			</description>
-		</property>
-	</bean>
-
-	<bean id="runFactory" class="org.taverna.server.master.mocks.ExampleRun$Builder">
-		<constructor-arg type="int" value="10" /> <!-- "initialLifetimeMinutes" -->
-	</bean>
-
-	<bean id="runCatalog" scope="singleton"
-		class="org.taverna.server.master.mocks.SimpleNonpersistentRunStore">
-		<property name="policy" ref="policy" />
-	</bean>
-
-	<bean id="listenerFactory" class="org.taverna.server.master.mocks.SimpleListenerFactory">
-		<property name="builders">
-			<description>
-				This map describes how to build each type of supported
-				event listener that is not installed by default. Any site policy for
-				a listeners should be installed using its properties, as shown. The
-				"key" is the type, the "class" is the builder for actual instances
-				(which must be an instance of
-				org.taverna.server.master.factories.SimpleListenerFactory.Builder)
-				and any policies and installation-specific configurations are
-				characterised by properties such as "sitePolicy" below.
-			</description>
-			<map>
-				<!--						<entry key="exampleListener">-->
-				<!--
-					<bean
-					class="org.taverna.server.master.example.ExampleListener$Builder">
-				-->
-				<!--								<property name="sitePolicy">-->
-				<!--									<value>Just an example!</value>-->
-				<!--								</property>-->
-				<!--							</bean>-->
-				<!--						</entry>-->
-			</map>
-		</property>
-	</bean>
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/test/resources/log4j.properties b/server-webapp/src/test/resources/log4j.properties
deleted file mode 100644
index 6707f55..0000000
--- a/server-webapp/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-log4j.rootLogger=info, R 
-log4j.appender.R=org.apache.log4j.ConsoleAppender
-log4j.appender.R.layout=org.apache.log4j.PatternLayout
-log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/pom.xml
----------------------------------------------------------------------
diff --git a/server-worker/pom.xml b/server-worker/pom.xml
deleted file mode 100644
index 8006c6d..0000000
--- a/server-worker/pom.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-worker</artifactId>
-	<name>Apache Taverna Server Workflow Executor/File System Access Process Implementation</name>
-	<description>This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
-
-	<properties>
-		<workerMainClass>org.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>
-	</properties>
-
-	<dependencies>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-runinterface</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>commons-collections</groupId>
-			<artifactId>commons-collections</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-usagerecord</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>commons-io</groupId>
-			<artifactId>commons-io</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-api</artifactId>
-			<version>${taverna.language.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-t2flow</artifactId>
-			<version>${taverna.language.version}</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-wfbundle</artifactId>
-			<version>${taverna.language.version}</version>
-			<scope>runtime</scope>
-		</dependency>
-	</dependencies>
-
-	<build>
-		<plugins>
-			<plugin>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<configuration>
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<mainClass>${workerMainClass}</mainClass>
-						</manifest>
-					</archive>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-assembly</id>
-						<phase>package</phase>
-						<goals>
-							<goal>single</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-		<pluginManagement>
-			<plugins>
-				<plugin>
-					<groupId>org.eclipse.m2e</groupId>
-					<artifactId>lifecycle-mapping</artifactId>
-					<version>1.0.0</version>
-					<configuration>
-						<lifecycleMappingMetadata>
-							<pluginExecutions>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>org.apache.maven.plugins</groupId>
-										<artifactId>maven-assembly-plugin</artifactId>
-                                    	<versionRange>[2.0,)</versionRange>
-                                    	<goals>
-                                    		<goal>single</goal>
-                                    	</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute />
-									</action>
-								</pluginExecution>
-							</pluginExecutions>
-						</lifecycleMappingMetadata>
-					</configuration>
-				</plugin>
-			</plugins>
-		</pluginManagement>
-	</build>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/META-INF/MANIFEST.MF b/server-worker/src/main/java/META-INF/MANIFEST.MF
deleted file mode 100644
index 5e94951..0000000
--- a/server-worker/src/main/java/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Class-Path: 
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java b/server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
deleted file mode 100644
index 600913a..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.api;
-
-import static java.nio.charset.Charset.defaultCharset;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * The defaults associated with this worker, together with various other
- * constants.
- * 
- * @author Donal Fellows
- */
-public abstract class Constants {
-	/**
-	 * Subdirectories of the working directory to create by default.
-	 */
-	public static final String[] SUBDIR_LIST = { "conf", "externaltool", "feed",
-			"interactions", "lib", "logs", "plugins", "repository", "var" };
-
-	/** The name of the default encoding for characters on this machine. */
-	public static final String SYSTEM_ENCODING = defaultCharset().name();
-
-	/**
-	 * Password to use to encrypt security information. This default is <7 chars
-	 * to work even without Unlimited Strength JCE.
-	 */
-	public static final char[] KEYSTORE_PASSWORD = { 'c', 'h', 'a', 'n', 'g', 'e' };
-
-	/**
-	 * The name of the directory (in the home directory) where security settings
-	 * will be written.
-	 */
-	public static final String SECURITY_DIR_NAME = ".taverna-server-security";
-
-	/** The name of the file that will be the created keystore. */
-	public static final String KEYSTORE_FILE = "t2keystore.ubr";
-
-	/** The name of the file that will be the created truststore. */
-	public static final String TRUSTSTORE_FILE = "t2truststore.ubr";
-
-	/**
-	 * The name of the file that contains the password to unlock the keystore
-	 * and truststore.
-	 */
-	public static final String PASSWORD_FILE = "password.txt";
-
-	// --------- UNUSED ---------
-	// /**
-	// * The name of the file that contains the mapping from URIs to keystore
-	// * aliases.
-	// */
-	// public static final String URI_ALIAS_MAP = "urlmap.txt";
-
-	/**
-	 * Used to instruct the Taverna credential manager to use a non-default
-	 * location for user credentials.
-	 */
-	public static final String CREDENTIAL_MANAGER_DIRECTORY = "-cmdir";
-
-	/**
-	 * Used to instruct the Taverna credential manager to take its master
-	 * password from standard input.
-	 */
-	public static final String CREDENTIAL_MANAGER_PASSWORD = "-cmpassword";
-
-	/**
-	 * Name of environment variable used to pass HELIO security tokens to
-	 * workflows.
-	 */
-	// This technique is known to be insecure; bite me.
-	public static final String HELIO_TOKEN_NAME = "HELIO_CIS_TOKEN";
-
-	/**
-	 * The name of the standard listener, which is installed by default.
-	 */
-	public static final String DEFAULT_LISTENER_NAME = "io";
-
-	/**
-	 * Time to wait for the subprocess to wait, in milliseconds.
-	 */
-	public static final int START_WAIT_TIME = 1500;
-
-	/**
-	 * Time to wait for success or failure of a death-causing activity (i.e.,
-	 * sending a signal).
-	 */
-	public static final int DEATH_TIME = 333;
-
-	/**
-	 * The name of the file (in this code's resources) that provides the default
-	 * security policy that we use.
-	 */
-	public static final String SECURITY_POLICY_FILE = "security.policy";
-
-	/**
-	 * The Java property holding security policy info.
-	 */
-	public static final String SEC_POLICY_PROP = "java.security.policy";
-	/**
-	 * The Java property to set to make this code not try to enforce security
-	 * policy.
-	 */
-	public static final String UNSECURE_PROP = "taverna.suppressrestrictions.rmi";
-	/**
-	 * The Java property that holds the name of the host name to enforce.
-	 */
-	public static final String RMI_HOST_PROP = "java.rmi.server.hostname";
-	/**
-	 * The default hostname to require in secure mode. This is the
-	 * <i>resolved</i> version of "localhost".
-	 */
-	public static final String LOCALHOST;
-	static {
-		String h = "127.0.0.1"; // fallback
-		try {
-			h = InetAddress.getByName("localhost").getHostAddress();
-		} catch (UnknownHostException e) {
-			e.printStackTrace();
-		} finally {
-			LOCALHOST = h;
-		}
-	}
-
-	/**
-	 * Time to wait during closing down this process. In milliseconds.
-	 */
-	public static final int DEATH_DELAY = 500;
-	/**
-	 * The name of the property describing where shared directories should be
-	 * located.
-	 */
-	public static final String SHARED_DIR_PROP = "taverna.sharedDirectory";
-
-	public static final String TIME = "/usr/bin/time";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java b/server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
deleted file mode 100644
index 3896c06..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.api;
-
-/**
- * 
- * @author Donal Fellows
- */
-public interface RunAccounting {
-	/**
-	 * Logs that a run has started executing.
-	 */
-	void runStarted();
-
-	/**
-	 * Logs that a run has finished executing.
-	 */
-	void runCeased();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java b/server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
deleted file mode 100644
index c513ed8..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.api;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-import org.taverna.server.localworker.impl.LocalWorker;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * The interface between the connectivity layer and the thunk to the
- * subprocesses.
- * 
- * @author Donal Fellows
- */
-public interface Worker {
-	/**
-	 * Fire up the workflow. This causes a transition into the operating state.
-	 * 
-	 * @param local
-	 *            The reference to the factory class for this worker.
-	 * @param executeWorkflowCommand
-	 *            The command to run to execute the workflow.
-	 * @param workflow
-	 *            The workflow document to execute.
-	 * @param workingDir
-	 *            What directory to use as the working directory.
-	 * @param inputBaclavaFile
-	 *            The baclava file to use for inputs, or <tt>null</tt> to use
-	 *            the other <b>input*</b> arguments' values.
-	 * @param inputRealFiles
-	 *            A mapping of input names to files that supply them. Note that
-	 *            we assume that nothing mapped here will be mapped in
-	 *            <b>inputValues</b>.
-	 * @param inputValues
-	 *            A mapping of input names to values to supply to them. Note
-	 *            that we assume that nothing mapped here will be mapped in
-	 *            <b>inputFiles</b>.
-	 * @param inputDelimiters
-	 *            A mapping of input names to characters used to split them into
-	 *            lists.
-	 * @param outputBaclavaFile
-	 *            What baclava file to write the output from the workflow into,
-	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
-	 *            subdirectory.
-	 * @param contextDirectory
-	 *            The directory containing the keystore and truststore. <i>Must
-	 *            not be <tt>null</tt>.</i>
-	 * @param keystorePassword
-	 *            The password to the keystore and truststore. <i>Must not be
-	 *            <tt>null</tt>.</i>
-	 * @param generateProvenance
-	 *            Whether to generate a run bundle containing provenance data.
-	 * @param environment
-	 *            Any environment variables that need to be added to the
-	 *            invokation.
-	 * @param masterToken
-	 *            The internal name of the workflow run.
-	 * @param runtimeSettings
-	 *            List of configuration details for the forked runtime.
-	 * @return Whether a successful start happened.
-	 * @throws Exception
-	 *             If any of quite a large number of things goes wrong.
-	 */
-	boolean initWorker(LocalWorker local, String executeWorkflowCommand,
-			byte[] workflow, File workingDir, File inputBaclavaFile,
-			Map<String, File> inputRealFiles, Map<String, String> inputValues,
-			Map<String, String> inputDelimiters, File outputBaclavaFile,
-			File contextDirectory, char[] keystorePassword,
-			boolean generateProvenance, Map<String, String> environment,
-			String masterToken, List<String> runtimeSettings) throws Exception;
-
-	/**
-	 * Kills off the subprocess if it exists and is alive.
-	 * 
-	 * @throws Exception
-	 *             if anything goes badly wrong when the worker is being killed
-	 *             off.
-	 */
-	void killWorker() throws Exception;
-
-	/**
-	 * Move the worker out of the stopped state and back to operating.
-	 * 
-	 * @throws Exception
-	 *             if it fails (which it always does; operation currently
-	 *             unsupported).
-	 */
-	void startWorker() throws Exception;
-
-	/**
-	 * Move the worker into the stopped state from the operating state.
-	 * 
-	 * @throws Exception
-	 *             if it fails (which it always does; operation currently
-	 *             unsupported).
-	 */
-	void stopWorker() throws Exception;
-
-	/**
-	 * @return The status of the workflow run. Note that this can be an
-	 *         expensive operation.
-	 */
-	RemoteStatus getWorkerStatus();
-
-	/**
-	 * @return The listener that is registered by default, in addition to all
-	 *         those that are explicitly registered by the user.
-	 */
-	RemoteListener getDefaultListener();
-
-	/**
-	 * @param receiver
-	 *            The destination where any final usage records are to be
-	 *            written in order to log them back to the server.
-	 */
-	void setURReceiver(UsageRecordReceiver receiver);
-
-	/**
-	 * Arrange for the deletion of any resources created during worker process
-	 * construction. Guaranteed to be the last thing done before finalization.
-	 * 
-	 * @throws ImplementationException
-	 *             If anything goes wrong.
-	 */
-	void deleteLocalResources() throws ImplementationException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java b/server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
deleted file mode 100644
index 4ce13a7..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.taverna.server.localworker.api;
-
-
-/**
- * Class that manufactures instances of {@link Worker}.
- * 
- * @author Donal Fellows
- */
-public interface WorkerFactory {
-	/**
-	 * Create an instance of the low-level worker class.
-	 * 
-	 * @return The worker object.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	Worker makeInstance() throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
deleted file mode 100644
index 1692856..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.forceMkdir;
-import static org.apache.commons.io.FileUtils.touch;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
-
-import java.io.File;
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
-import org.apache.commons.collections.MapIterator;
-import org.apache.commons.collections.map.ReferenceMap;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
-
-/**
- * This class acts as a remote-aware delegate for the workflow run's working
- * directory and its subdirectories.
- * 
- * @author Donal Fellows
- * @see FileDelegate
- */
-@SuppressWarnings("serial")
-public class DirectoryDelegate extends UnicastRemoteObject implements
-		RemoteDirectory {
-	private File dir;
-	private DirectoryDelegate parent;
-	private ReferenceMap localCache;
-
-	/**
-	 * @param dir
-	 * @param parent
-	 * @throws RemoteException
-	 *             If registration of the directory fails.
-	 */
-	public DirectoryDelegate(@Nonnull File dir,
-			@Nonnull DirectoryDelegate parent) throws RemoteException {
-		super();
-		this.localCache = new ReferenceMap();
-		this.dir = dir;
-		this.parent = parent;
-	}
-
-	@Override
-	public Collection<RemoteDirectoryEntry> getContents()
-			throws RemoteException {
-		List<RemoteDirectoryEntry> result = new ArrayList<>();
-		for (String s : dir.list()) {
-			if (s.equals(".") || s.equals(".."))
-				continue;
-			File f = new File(dir, s);
-			RemoteDirectoryEntry entry;
-			synchronized (localCache) {
-				entry = (RemoteDirectoryEntry) localCache.get(s);
-				if (f.isDirectory()) {
-					if (entry == null || !(entry instanceof DirectoryDelegate)) {
-						entry = new DirectoryDelegate(f, this);
-						localCache.put(s, entry);
-					}
-				} else if (f.isFile()) {
-					if (entry == null || !(entry instanceof FileDelegate)) {
-						entry = new FileDelegate(f, this);
-						localCache.put(s, entry);
-					}
-				} else {
-					// not file or dir; skip...
-					continue;
-				}
-			}
-			result.add(entry);
-		}
-		return result;
-	}
-
-	@Override
-	public RemoteFile makeEmptyFile(String name) throws IOException {
-		File f = getValidatedNewFile(dir, name);
-		touch(f);
-		FileDelegate delegate = new FileDelegate(f, this);
-		synchronized (localCache) {
-			localCache.put(name, delegate);
-		}
-		return delegate;
-	}
-
-	@Override
-	public RemoteDirectory makeSubdirectory(String name) throws IOException {
-		File f = getValidatedNewFile(dir, name);
-		forceMkdir(f);
-		DirectoryDelegate delegate = new DirectoryDelegate(f, this);
-		synchronized (localCache) {
-			localCache.put(name, delegate);
-		}
-		return delegate;
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public void destroy() throws IOException {
-		if (parent == null)
-			throw new IOException("tried to destroy main job working directory");
-		Collection<RemoteDirectoryEntry> values;
-		synchronized (localCache) {
-			values = new ArrayList<>(localCache.values());
-		}
-		for (RemoteDirectoryEntry obj : values) {
-			if (obj == null)
-				continue;
-			try {
-				obj.destroy();
-			} catch (IOException e) {
-			}
-		}
-		forceDelete(dir);
-		parent.forgetEntry(this);
-	}
-
-	@Override
-	public RemoteDirectory getContainingDirectory() {
-		return parent;
-	}
-
-	void forgetEntry(@Nonnull RemoteDirectoryEntry entry) {
-		synchronized (localCache) {
-			MapIterator i = localCache.mapIterator();
-			while (i.hasNext()) {
-				Object key = i.next();
-				if (entry == i.getValue()) {
-					localCache.remove(key);
-					break;
-				}
-			}
-		}
-	}
-
-	@Override
-	public String getName() {
-		if (parent == null)
-			return "";
-		return dir.getName();
-	}
-
-	@Override
-	public Date getModificationDate() throws RemoteException {
-		return new Date(dir.lastModified());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
deleted file mode 100644
index 7e47af9..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static java.lang.System.arraycopy;
-import static java.net.InetAddress.getLocalHost;
-import static org.apache.commons.io.FileUtils.copyFile;
-import static org.apache.commons.io.FileUtils.forceDelete;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Date;
-
-import javax.annotation.Nonnull;
-
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteFile;
-
-/**
- * This class acts as a remote-aware delegate for the files in a workflow run's
- * working directory and its subdirectories.
- * 
- * @author Donal Fellows
- * @see DirectoryDelegate
- */
-@java.lang.SuppressWarnings("serial")
-public class FileDelegate extends UnicastRemoteObject implements RemoteFile {
-	private File file;
-	private DirectoryDelegate parent;
-
-	/**
-	 * @param file
-	 * @param parent
-	 * @throws RemoteException
-	 *             If registration of the file fails.
-	 */
-	public FileDelegate(@Nonnull File file, @Nonnull DirectoryDelegate parent)
-			throws RemoteException {
-		super();
-		this.file = file;
-		this.parent = parent;
-	}
-
-	@Override
-	public byte[] getContents(int offset, int length) throws IOException {
-		if (length == -1)
-			length = (int) (file.length() - offset);
-		if (length < 0 || length > 1024 * 64)
-			length = 1024 * 64;
-		byte[] buffer = new byte[length];
-		int read;
-		try (FileInputStream fis = new FileInputStream(file)) {
-			if (offset > 0 && fis.skip(offset) != offset)
-				throw new IOException("did not move to correct offset in file");
-			read = fis.read(buffer);
-		}
-		if (read <= 0)
-			return new byte[0];
-		if (read < buffer.length) {
-			byte[] shortened = new byte[read];
-			arraycopy(buffer, 0, shortened, 0, read);
-			return shortened;
-		}
-		return buffer;
-	}
-
-	@Override
-	public long getSize() {
-		return file.length();
-	}
-
-	@Override
-	public void setContents(byte[] data) throws IOException {
-		try (FileOutputStream fos = new FileOutputStream(file)) {
-			fos.write(data);
-		}
-	}
-
-	@Override
-	public void appendContents(byte[] data) throws IOException {
-		try (FileOutputStream fos = new FileOutputStream(file, true)) {
-			fos.write(data);
-		}
-	}
-
-	@Override
-	public void destroy() throws IOException {
-		forceDelete(file);
-		parent.forgetEntry(this);
-		parent = null;
-	}
-
-	@Override
-	public RemoteDirectory getContainingDirectory() {
-		return parent;
-	}
-
-	@Override
-	public String getName() {
-		return file.getName();
-	}
-
-	@Override
-	public void copy(RemoteFile sourceFile) throws RemoteException, IOException {
-		String sourceHost = sourceFile.getNativeHost();
-		if (!getNativeHost().equals(sourceHost)) {
-			throw new IOException(
-					"cross-system copy not implemented; cannot copy from "
-							+ sourceHost + " to " + getNativeHost());
-		}
-		// Must copy; cannot count on other file to stay unmodified
-		copyFile(new File(sourceFile.getNativeName()), file);
-	}
-
-	@Override
-	public String getNativeName() {
-		return file.getAbsolutePath();
-	}
-
-	@Override
-	public String getNativeHost() {
-		try {
-			return getLocalHost().getHostAddress();
-		} catch (UnknownHostException e) {
-			throw new RuntimeException(
-					"unexpected failure to resolve local host address", e);
-		}
-	}
-
-	@Override
-	public Date getModificationDate() throws RemoteException {
-		return new Date(file.lastModified());
-	}
-}


[44/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java b/server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
deleted file mode 100644
index 48969fa..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.ok;
-import static javax.ws.rs.core.Response.seeOther;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-import static org.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
-import static org.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
-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.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-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.ws.rs.core.Variant;
-import javax.xml.ws.Holder;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.DirectoryBean;
-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.DirectoryEntry;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.DirectoryContents;
-import org.taverna.server.master.rest.FileSegment;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
-import org.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
-import org.taverna.server.master.rest.TavernaServerDirectoryREST;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful access to the filesystem.
- * 
- * @author Donal Fellows
- */
-class DirectoryREST implements TavernaServerDirectoryREST, DirectoryBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private TavernaServerSupport support;
-	private TavernaRun run;
-	private FilenameUtils fileUtils;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Override
-	public DirectoryREST connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response destroyDirectoryEntry(List<PathSegment> path)
-			throws NoUpdateException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		support.permitUpdate(run);
-		fileUtils.getDirEntry(run, path).destroy();
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public DirectoryContents getDescription(UriInfo ui)
-			throws FilesystemAccessException {
-		return new DirectoryContents(ui, run.getWorkingDirectory()
-				.getContents());
-	}
-
-	@Override
-	@CallCounted
-	public Response options(List<PathSegment> path) {
-		return opt("PUT", "POST", "DELETE");
-	}
-
-	/*
-	 * // Nasty! This can have several different responses...
-	 * 
-	 * @Override @CallCounted private Response
-	 * getDirectoryOrFileContents(List<PathSegment> path, UriInfo ui, Request
-	 * req) throws FilesystemAccessException, NoDirectoryEntryException {
-	 * 
-	 * DirectoryEntry de = fileUtils.getDirEntry(run, path);
-	 * 
-	 * // How did the user want the result?
-	 * 
-	 * List<Variant> variants = getVariants(de); Variant v =
-	 * req.selectVariant(variants); if (v == null) return
-	 * notAcceptable(variants).type(TEXT_PLAIN)
-	 * .entity("Do not know what type of response to produce.") .build();
-	 * 
-	 * // Produce the content to deliver up
-	 * 
-	 * Object result; if
-	 * (v.getMediaType().equals(APPLICATION_OCTET_STREAM_TYPE))
-	 * 
-	 * // Only for files...
-	 * 
-	 * result = de; else if (v.getMediaType().equals(APPLICATION_ZIP_TYPE))
-	 * 
-	 * // Only for directories...
-	 * 
-	 * result = ((Directory) de).getContentsAsZip(); else
-	 * 
-	 * // Only for directories... // XML or JSON; let CXF pick what to do
-	 * 
-	 * result = new DirectoryContents(ui, ((Directory) de).getContents());
-	 * return ok(result).type(v.getMediaType()).build();
-	 * 
-	 * }
-	 */
-
-	private boolean matchType(MediaType a, MediaType b) {
-		if (log.isDebugEnabled())
-			log.debug("comparing " + a.getType() + "/" + a.getSubtype()
-					+ " and " + b.getType() + "/" + b.getSubtype());
-		return (a.isWildcardType() || b.isWildcardType() || a.getType().equals(
-				b.getType()))
-				&& (a.isWildcardSubtype() || b.isWildcardSubtype() || a
-						.getSubtype().equals(b.getSubtype()));
-	}
-
-	/**
-	 * What are we willing to serve up a directory or file as?
-	 * 
-	 * @param de
-	 *            The reference to the object to serve.
-	 * @return The variants we can serve it as.
-	 * @throws FilesystemAccessException
-	 *             If we fail to read data necessary to detection of its media
-	 *             type.
-	 */
-	private List<Variant> getVariants(DirectoryEntry de)
-			throws FilesystemAccessException {
-		if (de instanceof Directory)
-			return DIRECTORY_VARIANTS;
-		else if (!(de instanceof File))
-			throw new FilesystemAccessException("not a directory or file!");
-		File f = (File) de;
-		List<Variant> variants = new ArrayList<>(INITIAL_FILE_VARIANTS);
-		String contentType = support.getEstimatedContentType(f);
-		if (!contentType.equals(APPLICATION_OCTET_STREAM)) {
-			String[] ct = contentType.split("/");
-			variants.add(0,
-					new Variant(new MediaType(ct[0], ct[1]), (String) null, null));
-		}
-		return variants;
-	}
-
-	/** How did the user want the result? */
-	private MediaType pickType(HttpHeaders headers, DirectoryEntry de)
-			throws FilesystemAccessException, NegotiationFailedException {
-		List<Variant> variants = getVariants(de);
-		// Manual content negotiation!!! Ugh!
-		for (MediaType mt : headers.getAcceptableMediaTypes())
-			for (Variant v : variants)
-				if (matchType(mt, v.getMediaType()))
-					return v.getMediaType();
-		throw new NegotiationFailedException(
-				"Do not know what type of response to produce.", variants);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response getDirectoryOrFileContents(List<PathSegment> path,
-			UriInfo ui, HttpHeaders headers) throws FilesystemAccessException,
-			NoDirectoryEntryException, NegotiationFailedException {
-		DirectoryEntry de = fileUtils.getDirEntry(run, path);
-
-		// How did the user want the result?
-		MediaType wanted = pickType(headers, de);
-
-		log.info("producing content of type " + wanted);
-		// Produce the content to deliver up
-		Object result;
-		if (de instanceof File) {
-			// Only for files...
-			result = de;
-			List<String> range = headers.getRequestHeader("Range");
-			if (range != null && range.size() == 1)
-				return new FileSegment((File) de, range.get(0))
-						.toResponse(wanted);
-		} else {
-			// Only for directories...
-			Directory d = (Directory) de;
-			if (wanted.getType().equals(APPLICATION_ZIP_TYPE.getType())
-					&& wanted.getSubtype().equals(
-							APPLICATION_ZIP_TYPE.getSubtype()))
-				result = d.getContentsAsZip();
-			else
-				// XML or JSON; let CXF pick what to do
-				result = new DirectoryContents(ui, d.getContents());
-		}
-		return ok(result).type(wanted).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response makeDirectoryOrUpdateFile(List<PathSegment> parent,
-			MakeOrUpdateDirEntry op, UriInfo ui) throws NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException {
-		support.permitUpdate(run);
-		DirectoryEntry container = fileUtils.getDirEntry(run, parent);
-		if (!(container instanceof Directory))
-			throw new FilesystemAccessException("You may not "
-					+ ((op instanceof MakeDirectory) ? "make a subdirectory of"
-							: "place a file in") + " a file.");
-		if (op.name == null || op.name.length() == 0)
-			throw new FilesystemAccessException("missing name attribute");
-		Directory d = (Directory) container;
-		UriBuilder ub = secure(ui).path("{name}");
-
-		// Make a directory in the context directory
-
-		if (op instanceof MakeDirectory) {
-			Directory target = d.makeSubdirectory(support.getPrincipal(),
-					op.name);
-			return created(ub.build(target.getName())).build();
-		}
-
-		// Make or set the contents of a file
-
-		File f = null;
-		for (DirectoryEntry e : d.getContents()) {
-			if (e.getName().equals(op.name)) {
-				if (e instanceof Directory)
-					throw new FilesystemAccessException(
-							"You may not overwrite a directory with a file.");
-				f = (File) e;
-				break;
-			}
-		}
-		if (f == null) {
-			f = d.makeEmptyFile(support.getPrincipal(), op.name);
-			f.setContents(op.contents);
-			return created(ub.build(f.getName())).build();
-		}
-		f.setContents(op.contents);
-		return seeOther(ub.build(f.getName())).build();
-	}
-
-	private File getFileForWrite(List<PathSegment> filePath,
-			Holder<Boolean> isNew) throws FilesystemAccessException,
-			NoDirectoryEntryException, NoUpdateException {
-		support.permitUpdate(run);
-		if (filePath == null || filePath.size() == 0)
-			throw new FilesystemAccessException(
-					"Cannot create a file that is not in a directory.");
-
-		List<PathSegment> dirPath = new ArrayList<>(filePath);
-		String name = dirPath.remove(dirPath.size() - 1).getPath();
-		DirectoryEntry de = fileUtils.getDirEntry(run, dirPath);
-		if (!(de instanceof Directory)) {
-			throw new FilesystemAccessException(
-					"Cannot create a file that is not in a directory.");
-		}
-		Directory d = (Directory) de;
-
-		File f = null;
-		isNew.value = false;
-		for (DirectoryEntry e : d.getContents())
-			if (e.getName().equals(name)) {
-				if (e instanceof File) {
-					f = (File) e;
-					break;
-				}
-				throw new FilesystemAccessException(
-						"Cannot create a file that is not in a directory.");
-			}
-
-		if (f == null) {
-			f = d.makeEmptyFile(support.getPrincipal(), name);
-			isNew.value = true;
-		} else
-			f.setContents(new byte[0]);
-		return f;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response setFileContents(List<PathSegment> filePath,
-			InputStream contents, UriInfo ui) throws NoDirectoryEntryException,
-			NoUpdateException, FilesystemAccessException {
-		Holder<Boolean> isNew = new Holder<>(true);
-		support.copyStreamToFile(contents, getFileForWrite(filePath, isNew));
-
-		if (isNew.value)
-			return created(ui.getAbsolutePath()).build();
-		else
-			return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response setFileContentsFromURL(List<PathSegment> filePath,
-			List<URI> referenceList, UriInfo ui)
-			throws NoDirectoryEntryException, NoUpdateException,
-			FilesystemAccessException {
-		support.permitUpdate(run);
-		if (referenceList.isEmpty() || referenceList.size() > 1)
-			return status(422).entity("URI list must have single URI in it")
-					.build();
-		URI uri = referenceList.get(0);
-		try {
-			uri.toURL();
-		} catch (MalformedURLException e) {
-			return status(422).entity("URI list must have value URL in it")
-					.build();
-		}
-		Holder<Boolean> isNew = new Holder<>(true);
-		File f = getFileForWrite(filePath, isNew);
-
-		try {
-			support.copyDataToFile(uri, f);
-		} catch (MalformedURLException ex) {
-			// Should not happen; called uri.toURL() successfully above
-			throw new NoUpdateException("failed to parse URI", ex);
-		} catch (IOException ex) {
-			throw new FilesystemAccessException(
-					"failed to transfer data from URI", ex);
-		}
-
-		if (isNew.value)
-			return created(ui.getAbsolutePath()).build();
-		else
-			return noContent().build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java b/server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
deleted file mode 100644
index 3893b3d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.taverna.server.master;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * Simple concatenation of files.
- * 
- * @author Donal Fellows
- */
-public class FileConcatenation implements Iterable<File> {
-	private List<File> files = new ArrayList<>();
-
-	public void add(File f) {
-		files.add(f);
-	}
-
-	public boolean isEmpty() {
-		return files.isEmpty();
-	}
-
-	/**
-	 * @return The total length of the files, or -1 if this cannot be
-	 *         determined.
-	 */
-	public long size() {
-		long size = 0;
-		for (File f : files)
-			try {
-				size += f.getSize();
-			} catch (FilesystemAccessException e) {
-				// Ignore; shouldn't happen but can't guarantee
-			}
-		return (size == 0 && !files.isEmpty() ? -1 : size);
-	}
-
-	/**
-	 * Get the concatenated files.
-	 * 
-	 * @param encoding
-	 *            The encoding to use.
-	 * @return The concatenated files.
-	 * @throws UnsupportedEncodingException
-	 *             If the encoding doesn't exist.
-	 */
-	public String get(String encoding) throws UnsupportedEncodingException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		for (File f : files)
-			try {
-				baos.write(f.getContents(0, -1));
-			} catch (FilesystemAccessException | IOException e) {
-				continue;
-			}
-		return baos.toString(encoding);
-	}
-
-	@Override
-	public Iterator<File> iterator() {
-		return files.iterator();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/InputREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/InputREST.java b/server-webapp/src/main/java/org/taverna/server/master/InputREST.java
deleted file mode 100644
index 0f48207..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/InputREST.java
+++ /dev/null
@@ -1,252 +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.util.UUID.randomUUID;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.Date;
-
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.cxf.jaxrs.impl.MetadataMap;
-import org.apache.cxf.jaxrs.model.URITemplate;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.InputBean;
-import org.taverna.server.master.common.DirEntryReference;
-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.NoDirectoryEntryException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-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.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
-import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.InputDescription;
-
-/**
- * RESTful interface to the input descriptor of a single workflow run.
- * 
- * @author Donal Fellows
- */
-class InputREST implements TavernaServerInputREST, InputBean {
-	private UriInfo ui;
-	private TavernaServerSupport support;
-	private TavernaRun run;
-	private ContentsDescriptorBuilder cdBuilder;
-	private FilenameUtils fileUtils;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
-		this.cdBuilder = cdBuilder;
-	}
-
-	@Override
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Override
-	public InputREST connect(TavernaRun run, UriInfo ui) {
-		this.run = run;
-		this.ui = ui;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InputsDescriptor get() {
-		return new InputsDescriptor(ui, run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InputDescription getExpected() {
-		return cdBuilder.makeInputDescriptor(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getBaclavaFile() {
-		String i = run.getInputBaclavaFile();
-		return i == null ? "" : i;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InDesc getInput(String name, UriInfo ui) throws BadInputPortNameException {
-		Input i = support.getInput(run, name);
-		if (i == null)
-			throw new BadInputPortNameException("unknown input port name");
-		return new InDesc(i, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String setBaclavaFile(String filename) throws NoUpdateException,
-			BadStateChangeException, FilesystemAccessException {
-		support.permitUpdate(run);
-		run.setInputBaclavaFile(filename);
-		String i = run.getInputBaclavaFile();
-		return i == null ? "" : i;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public InDesc setInput(String name, InDesc inputDescriptor, UriInfo ui)
-			throws NoUpdateException, BadStateChangeException,
-			FilesystemAccessException, BadInputPortNameException,
-			BadPropertyValueException {
-		inputDescriptor.descriptorRef = null;
-		AbstractContents ac = inputDescriptor.assignment;
-		if (name == null || name.isEmpty())
-			throw new BadInputPortNameException("bad input name");
-		if (ac == null)
-			throw new BadPropertyValueException("no content!");
-		if (inputDescriptor.delimiter != null
-				&& inputDescriptor.delimiter.isEmpty())
-			inputDescriptor.delimiter = null;
-		if (ac instanceof InDesc.Reference)
-			return setRemoteInput(name, (InDesc.Reference) ac,
-					inputDescriptor.delimiter, ui);
-		if (!(ac instanceof InDesc.File || ac instanceof InDesc.Value))
-			throw new BadPropertyValueException("unknown content type");
-		support.permitUpdate(run);
-		Input i = support.getInput(run, name);
-		if (i == null)
-			i = run.makeInput(name);
-		if (ac instanceof InDesc.File)
-			i.setFile(ac.contents);
-		else
-			i.setValue(ac.contents);
-		i.setDelimiter(inputDescriptor.delimiter);
-		return new InDesc(i, ui);
-	}
-
-	private InDesc setRemoteInput(String name, Reference ref, String delimiter,
-			UriInfo ui) throws BadStateChangeException,
-			BadPropertyValueException, FilesystemAccessException {
-		URITemplate tmpl = new URITemplate(ui.getBaseUri()
-				+ "/runs/{runName}/wd/{path:.+}");
-		MultivaluedMap<String, String> mvm = new MetadataMap<>();
-		if (!tmpl.match(ref.contents, mvm)) {
-			throw new BadPropertyValueException(
-					"URI in reference does not refer to local disk resource");
-		}
-		try {
-			File from = fileUtils.getFile(
-					support.getRun(mvm.get("runName").get(0)),
-					SyntheticDirectoryEntry.make(mvm.get("path").get(0)));
-			File to = run.getWorkingDirectory().makeEmptyFile(
-					support.getPrincipal(), randomUUID().toString());
-
-			to.copy(from);
-
-			Input i = support.getInput(run, name);
-			if (i == null)
-				i = run.makeInput(name);
-			i.setFile(to.getFullName());
-			i.setDelimiter(delimiter);
-			return new InDesc(i, ui);
-		} catch (UnknownRunException e) {
-			throw new BadStateChangeException("may not copy from that run", e);
-		} catch (NoDirectoryEntryException e) {
-			throw new BadStateChangeException("source does not exist", e);
-		}
-	}
-
-	@Override
-	@CallCounted
-	public Response options() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response expectedOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response baclavaOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response inputOptions(@PathParam("name") String name) {
-		return opt("PUT");
-	}
-}
-
-/**
- * A way to create synthetic directory entries, used during deletion.
- * 
- * @author Donal Fellows
- */
-class SyntheticDirectoryEntry implements DirectoryEntry {
-	public static DirEntryReference make(String path) {
-		return DirEntryReference.newInstance(new SyntheticDirectoryEntry(path));
-	}
-
-	private SyntheticDirectoryEntry(String p) {
-		this.p = p;
-		this.d = new Date();
-	}
-
-	private String p;
-	private Date d;
-
-	@Override
-	public String getName() {
-		return null;
-	}
-
-	@Override
-	public String getFullName() {
-		return p;
-	}
-
-	@Override
-	public void destroy() {
-	}
-
-	@Override
-	public int compareTo(DirectoryEntry o) {
-		return p.compareTo(o.getFullName());
-	}
-
-	@Override
-	public Date getModificationDate() {
-		return d;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java b/server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
deleted file mode 100644
index b686491..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static org.taverna.server.master.common.Roles.SELF;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.taverna.server.master.api.FeedBean;
-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.interaction.InteractionFeedSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * How to connect an interaction feed to the webapp.
- * 
- * @author Donal Fellows
- */
-public class InteractionFeed implements InteractionFeedREST, FeedBean {
-	private InteractionFeedSupport interactionFeed;
-	private TavernaRun run;
-
-	@Override
-	public void setInteractionFeedSupport(InteractionFeedSupport feed) {
-		this.interactionFeed = feed;
-	}
-
-	InteractionFeed connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Feed getFeed() throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		return interactionFeed.getRunFeed(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Response addEntry(Entry entry) throws MalformedURLException,
-			FilesystemAccessException, NoDirectoryEntryException,
-			NoUpdateException {
-		Entry realEntry = interactionFeed.addRunFeedEntry(run, entry);
-		URI location;
-		try {
-			location = realEntry.getSelfLink().getHref().toURI();
-		} catch (URISyntaxException e) {
-			throw new RuntimeException("failed to make URI from link?!", e);
-		}
-		return Response.created(location).entity(realEntry)
-				.type("application/atom+xml;type=entry").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public Entry getEntry(String id) throws FilesystemAccessException,
-			NoDirectoryEntryException {
-		return interactionFeed.getRunFeedEntry(run, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public String deleteEntry(String id) throws FilesystemAccessException,
-			NoDirectoryEntryException, NoUpdateException {
-		interactionFeed.removeRunFeedEntry(run, id);
-		return "entry successfully deleted";
-	}
-
-	@Override
-	@CallCounted
-	public Response feedOptions() {
-		return opt("POST");
-	}
-
-	@Override
-	@CallCounted
-	public Response entryOptions(String id) {
-		return opt("DELETE");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java b/server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
deleted file mode 100644
index 3e983a9..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ListenerPropertyBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single property of a workflow run.
- * 
- * @author Donal Fellows
- */
-class ListenerPropertyREST implements TavernaServerListenersREST.Property,
-		ListenerPropertyBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private TavernaServerSupport support;
-	private Listener listen;
-	private String propertyName;
-	private TavernaRun run;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public ListenerPropertyREST connect(Listener listen, TavernaRun run,
-			String propertyName) {
-		this.listen = listen;
-		this.propertyName = propertyName;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getValue() {
-		try {
-			return listen.getProperty(propertyName);
-		} catch (NoListenerException e) {
-			log.error("unexpected exception; property \"" + propertyName
-					+ "\" should exist", e);
-			return null;
-		}
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String setValue(String value) throws NoUpdateException,
-			NoListenerException {
-		support.permitUpdate(run);
-		listen.setProperty(propertyName, value);
-		return listen.getProperty(propertyName);
-	}
-
-	@Override
-	@CallCounted
-	public Response options() {
-		return opt("PUT");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java b/server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
deleted file mode 100644
index 4b7d7f3..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.ListenersBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.exceptions.NoUpdateException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.ListenerDefinition;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single workflow run's event listeners.
- * 
- * @author Donal Fellows
- */
-abstract class ListenersREST implements TavernaServerListenersREST,
-		ListenersBean {
-	private TavernaRun run;
-	private TavernaServerSupport support;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public ListenersREST connect(TavernaRun run) {
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addListener(ListenerDefinition typeAndConfiguration,
-			UriInfo ui) throws NoUpdateException, NoListenerException {
-		String name = support.makeListener(run, typeAndConfiguration.type,
-				typeAndConfiguration.configuration).getName();
-		return created(secure(ui).path("{listenerName}").build(name)).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenerREST getListener(String name)
-			throws NoListenerException {
-		Listener l = support.getListener(run, name);
-		if (l == null)
-			throw new NoListenerException();
-		return makeListenerInterface().connect(l, run);
-	}
-
-	@Nonnull
-	protected abstract SingleListenerREST makeListenerInterface();
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Listeners getDescription(UriInfo ui) {
-		List<ListenerDescription> result = new ArrayList<>();
-		UriBuilder ub = secure(ui).path("{name}");
-		for (Listener l : run.getListeners())
-			result.add(new ListenerDescription(l,
-					fromUri(ub.build(l.getName()))));
-		return new Listeners(result, ub);
-	}
-
-	@Override
-	@CallCounted
-	public Response listenersOptions() {
-		return opt();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/ManagementState.java b/server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
deleted file mode 100644
index 9d4a651..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import javax.annotation.PostConstruct;
-import javax.jdo.Query;
-import javax.jdo.annotations.PersistenceAware;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.JDOSupport;
-
-/** The persistent, manageable state of the Taverna Server web application. */
-@PersistenceAware
-class ManagementState extends JDOSupport<WebappState> implements
-		ManagementModel {
-	public ManagementState() {
-		super(WebappState.class);
-	}
-
-	/** Whether we should log all workflows sent to us. */
-	private boolean logIncomingWorkflows = false;
-
-	/** Whether we allow the creation of new workflow runs. */
-	private boolean allowNewWorkflowRuns = true;
-
-	/**
-	 * Whether outgoing exceptions should be logged before being converted to
-	 * responses.
-	 */
-	private boolean logOutgoingExceptions = false;
-
-	/**
-	 * The file that all usage records should be appended to, or <tt>null</tt>
-	 * if they should be just dropped.
-	 */
-	private String usageRecordLogFile = null;
-
-	@Override
-	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-		this.logIncomingWorkflows = logIncomingWorkflows;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getLogIncomingWorkflows() {
-		self.load();
-		return logIncomingWorkflows;
-	}
-
-	@Override
-	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getAllowNewWorkflowRuns() {
-		self.load();
-		return allowNewWorkflowRuns;
-	}
-
-	@Override
-	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-		this.logOutgoingExceptions = logOutgoingExceptions;
-		if (loadedState)
-			self.store();
-	}
-
-	@Override
-	public boolean getLogOutgoingExceptions() {
-		self.load();
-		return logOutgoingExceptions || true;
-	}
-
-	@Override
-	public String getUsageRecordLogFile() {
-		self.load();
-		return usageRecordLogFile;
-	}
-
-	@Override
-	public void setUsageRecordLogFile(String usageRecordLogFile) {
-		this.usageRecordLogFile = usageRecordLogFile;
-		if (loadedState)
-			self.store();
-	}
-
-	private static final int KEY = 42; // whatever
-
-	private WebappState get() {
-		Query q = query("id == " + KEY);
-		q.setUnique(true);
-		return (WebappState) q.execute();
-	}
-
-	private boolean loadedState;
-	private ManagementState self;
-
-	@Required
-	public void setSelf(ManagementState self) {
-		this.self = self;
-	}
-
-	@PostConstruct
-	@WithinSingleTransaction
-	public void load() {
-		if (loadedState || !isPersistent())
-			return;
-		WebappState state = get();
-		if (state == null)
-			return;
-		allowNewWorkflowRuns = state.getAllowNewWorkflowRuns();
-		logIncomingWorkflows = state.getLogIncomingWorkflows();
-		logOutgoingExceptions = state.getLogOutgoingExceptions();
-		usageRecordLogFile = state.getUsageRecordLogFile();
-		loadedState = true;
-	}
-
-	@WithinSingleTransaction
-	public void store() {
-		if (!isPersistent())
-			return;
-		WebappState state = get();
-		if (state == null) {
-			state = new WebappState();
-			// save state
-			state.id = KEY; // whatever...
-			state = persist(state);
-		}
-		state.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
-		state.setLogIncomingWorkflows(logIncomingWorkflows);
-		state.setLogOutgoingExceptions(logOutgoingExceptions);
-		state.setUsageRecordLogFile(usageRecordLogFile);
-		loadedState = true;
-	}
-}
-
-// WARNING! If you change the name of this class, update persistence.xml as
-// well!
-@PersistenceCapable(table = "MANAGEMENTSTATE__WEBAPPSTATE")
-class WebappState implements ManagementModel {
-	public WebappState() {
-	}
-
-	@PrimaryKey
-	protected int id;
-
-	/** Whether we should log all workflows sent to us. */
-	@Persistent
-	private boolean logIncomingWorkflows;
-
-	/** Whether we allow the creation of new workflow runs. */
-	@Persistent
-	private boolean allowNewWorkflowRuns;
-
-	/**
-	 * Whether outgoing exceptions should be logged before being converted to
-	 * responses.
-	 */
-	@Persistent
-	private boolean logOutgoingExceptions;
-
-	/** Where to write usage records. */
-	@Persistent
-	private String usageRecordLogFile;
-
-	@Override
-	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
-		this.logIncomingWorkflows = logIncomingWorkflows;
-	}
-
-	@Override
-	public boolean getLogIncomingWorkflows() {
-		return logIncomingWorkflows;
-	}
-
-	@Override
-	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
-		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
-	}
-
-	@Override
-	public boolean getAllowNewWorkflowRuns() {
-		return allowNewWorkflowRuns;
-	}
-
-	@Override
-	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
-		this.logOutgoingExceptions = logOutgoingExceptions;
-	}
-
-	@Override
-	public boolean getLogOutgoingExceptions() {
-		return logOutgoingExceptions;
-	}
-
-	@Override
-	public String getUsageRecordLogFile() {
-		return usageRecordLogFile;
-	}
-
-	@Override
-	public void setUsageRecordLogFile(String usageRecordLogFile) {
-		this.usageRecordLogFile = usageRecordLogFile;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/RunREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/RunREST.java b/server-webapp/src/main/java/org/taverna/server/master/RunREST.java
deleted file mode 100644
index 563a822..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/RunREST.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-import static javax.ws.rs.core.Response.noContent;
-import static javax.ws.rs.core.Response.ok;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.joda.time.format.ISODateTimeFormat.dateTime;
-import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
-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.Status.Operating;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.Date;
-
-import javax.annotation.security.RolesAllowed;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.joda.time.DateTime;
-import org.ogf.usage.JobUsageRecord;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.RunBean;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-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.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.InteractionFeedREST;
-import org.taverna.server.master.rest.TavernaServerInputREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerRunREST;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * RESTful interface to a single workflow run.
- * 
- * @author Donal Fellows
- */
-abstract class RunREST implements TavernaServerRunREST, RunBean {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private String runName;
-	private TavernaRun run;
-	private TavernaServerSupport support;
-	private ContentsDescriptorBuilder cdBuilder;
-
-	@Override
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	@Required
-	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
-		this.cdBuilder = cdBuilder;
-	}
-
-	@Override
-	public void setRunName(String runName) {
-		this.runName = runName;
-	}
-
-	@Override
-	public void setRun(TavernaRun run) {
-		this.run = run;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public RunDescription getDescription(UriInfo ui) {
-		return new RunDescription(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response destroy() throws NoUpdateException {
-		try {
-			support.unregisterRun(runName, run);
-		} catch (UnknownRunException e) {
-			log.fatal("can't happen", e);
-		}
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerListenersREST getListeners() {
-		return makeListenersInterface().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerSecurityREST getSecurity() throws NotOwnerException {
-		TavernaSecurityContext secContext = run.getSecurityContext();
-		if (!support.getPrincipal().equals(secContext.getOwner()))
-			throw new NotOwnerException();
-
-		// context.getBean("run.security", run, secContext);
-		return makeSecurityInterface().connect(secContext, run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getExpiryTime() {
-		return dateTime().print(new DateTime(run.getExpiry()));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getCreateTime() {
-		return dateTime().print(new DateTime(run.getCreationTimestamp()));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getFinishTime() {
-		Date f = run.getFinishTimestamp();
-		return f == null ? "" : dateTime().print(new DateTime(f));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStartTime() {
-		Date f = run.getStartTimestamp();
-		return f == null ? "" : dateTime().print(new DateTime(f));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStatus() {
-		return run.getStatus().toString();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Workflow getWorkflow() {
-		return run.getWorkflow();
-	}
-
-	@Override
-	@CallCounted
-	public String getMainProfileName() {
-		String name = run.getWorkflow().getMainProfileName();
-		return (name == null ? "" : name);
-	}
-
-	@Override
-	@CallCounted
-	public ProfileList getProfiles() {
-		return support.getProfileDescriptor(run.getWorkflow());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public DirectoryREST getWorkingDirectory() {
-		return makeDirectoryInterface().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setExpiryTime(String expiry) throws NoUpdateException,
-			IllegalArgumentException {
-		DateTime wanted = dateTimeParser().parseDateTime(expiry.trim());
-		Date achieved = support.updateExpiry(run, wanted.toDate());
-		return dateTime().print(new DateTime(achieved));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response setStatus(String status) throws NoUpdateException {
-		Status newStatus = Status.valueOf(status.trim());
-		support.permitUpdate(run);
-		if (newStatus == Operating && run.getStatus() == Initialized) {
-			if (!support.getAllowStartWorkflowRuns())
-				throw new OverloadedException();
-			String issue = run.setStatus(newStatus);
-			if (issue == null)
-				issue = "starting run...";
-			return status(202).entity(issue).type("text/plain").build();
-		}
-		run.setStatus(newStatus); // Ignore the result
-		return ok(run.getStatus().toString()).type("text/plain").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public TavernaServerInputREST getInputs(UriInfo ui) {
-		return makeInputInterface().connect(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getOutputFile() {
-		String o = run.getOutputBaclavaFile();
-		return o == null ? "" : o;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setOutputFile(String filename) throws NoUpdateException,
-			FilesystemAccessException, BadStateChangeException {
-		support.permitUpdate(run);
-		if (filename != null && filename.length() == 0)
-			filename = null;
-		run.setOutputBaclavaFile(filename);
-		String o = run.getOutputBaclavaFile();
-		return o == null ? "" : o;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public OutputDescription getOutputDescription(UriInfo ui)
-			throws BadStateChangeException, FilesystemAccessException,
-			NoDirectoryEntryException {
-		if (run.getStatus() == Initialized)
-			throw new BadStateChangeException(
-					"may not get output description in initial state");
-		return cdBuilder.makeOutputDescriptor(run, ui);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed({ USER, SELF })
-	public InteractionFeedREST getInteractionFeed() {
-		return makeInteractionFeed().connect(run);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getName() {
-		return run.getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String setName(String name) throws NoUpdateException {
-		support.permitUpdate(run);
-		run.setName(name);
-		return run.getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStdout() throws NoListenerException {
-		return support.getProperty(run, "io", "stdout");
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public String getStderr() throws NoListenerException {
-		return support.getProperty(run, "io", "stderr");
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getUsage() throws NoListenerException, JAXBException {
-		String ur = support.getProperty(run, "io", "usageRecord");
-		if (ur.isEmpty())
-			return noContent().build();
-		return ok(JobUsageRecord.unmarshal(ur), APPLICATION_XML).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getLogContents() {
-		FileConcatenation fc = support.getLogs(run);
-		if (fc.isEmpty())
-			return Response.noContent().build();
-		return Response.ok(fc, TEXT_PLAIN).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public Response getRunBundle() {
-		FileConcatenation fc = support.getProv(run);
-		if (fc.isEmpty())
-			return Response.status(404).entity("no provenance currently available").build();
-		return Response.ok(fc, "application/vnd.wf4ever.robundle+zip").build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public boolean getGenerateProvenance() {
-		return run.getGenerateProvenance();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	@RolesAllowed(USER)
-	public boolean setGenerateProvenance(boolean newValue) throws NoUpdateException {
-		support.permitUpdate(run);
-		run.setGenerateProvenance(newValue);
-		return run.getGenerateProvenance();
-	}
-
-	/**
-	 * Construct a RESTful interface to a run's filestore.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract DirectoryREST makeDirectoryInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's input descriptors.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract InputREST makeInputInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's listeners.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract ListenersREST makeListenersInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's security.
-	 * 
-	 * @return The handle to the interface, as decorated by Spring.
-	 */
-	protected abstract RunSecurityREST makeSecurityInterface();
-
-	/**
-	 * Construct a RESTful interface to a run's interaction feed.
-	 * 
-	 * @return The handle to the interaface, as decorated by Spring.
-	 */
-	protected abstract InteractionFeed makeInteractionFeed();
-
-	@Override
-	@CallCounted
-	public Response runOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response workflowOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response profileOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response expiryOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response createTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response startTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response finishTimeOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response statusOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response outputOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response nameOptions() {
-		return opt("PUT");
-	}
-
-	@Override
-	@CallCounted
-	public Response stdoutOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response stderrOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response usageOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response logOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response runBundleOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response generateProvenanceOptions() {
-		return opt("PUT");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java b/server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
deleted file mode 100644
index 5a366b2..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master;
-
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.Response.created;
-import static javax.ws.rs.core.Response.noContent;
-import static org.taverna.server.master.common.Status.Initialized;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.SecurityBean;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.rest.TavernaServerSecurityREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single workflow run's security settings.
- * 
- * @author Donal Fellows
- */
-class RunSecurityREST implements TavernaServerSecurityREST, SecurityBean {
-	private TavernaServerSupport support;
-	private TavernaSecurityContext context;
-	private TavernaRun run;
-
-	@Override
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	@Override
-	public RunSecurityREST connect(TavernaSecurityContext context,
-			TavernaRun run) {
-		this.context = context;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Descriptor describe(UriInfo ui) {
-		return new Descriptor(secure(ui).path("{element}"), context.getOwner()
-				.getName(), context.getCredentials(), context.getTrusted());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getOwner() {
-		return context.getOwner().getName();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialList listCredentials() {
-		return new CredentialList(context.getCredentials());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialHolder getParticularCredential(String id)
-			throws NoCredentialException {
-		for (Credential c : context.getCredentials())
-			if (c.id.equals(id))
-				return new CredentialHolder(c);
-		throw new NoCredentialException();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public CredentialHolder setParticularCredential(String id,
-			CredentialHolder cred, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Credential c = cred.credential;
-		c.id = id;
-		c.href = ui.getAbsolutePath().toString();
-		context.validateCredential(c);
-		context.deleteCredential(c);
-		context.addCredential(c);
-		return new CredentialHolder(c);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addCredential(CredentialHolder cred, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Credential c = cred.credential;
-		c.id = randomUUID().toString();
-		URI uri = secure(ui).path("{id}").build(c.id);
-		c.href = uri.toString();
-		context.validateCredential(c);
-		context.addCredential(c);
-		return created(uri).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteAllCredentials(UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		for (Credential c : context.getCredentials())
-			context.deleteCredential(c);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteCredential(String id, UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		context.deleteCredential(new Credential.Dummy(id));
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TrustList listTrusted() {
-		return new TrustList(context.getTrusted());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Trust getParticularTrust(String id) throws NoCredentialException {
-		for (Trust t : context.getTrusted())
-			if (t.id.equals(id))
-				return t;
-		throw new NoCredentialException();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Trust setParticularTrust(String id, Trust t, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		t.id = id;
-		t.href = ui.getAbsolutePath().toString();
-		context.validateTrusted(t);
-		context.deleteTrusted(t);
-		context.addTrusted(t);
-		return t;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response addTrust(Trust t, UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		t.id = randomUUID().toString();
-		URI uri = secure(ui).path("{id}").build(t.id);
-		t.href = uri.toString();
-		context.validateTrusted(t);
-		context.addTrusted(t);
-		return created(uri).build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteAllTrusts(UriInfo ui) throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		for (Trust t : context.getTrusted())
-			context.deleteTrusted(t);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deleteTrust(String id, UriInfo ui)
-			throws BadStateChangeException {
-		if (run.getStatus() != Initialized)
-			throw new BadStateChangeException();
-		Trust toDelete = new Trust();
-		toDelete.id = id;
-		context.deleteTrusted(toDelete);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public PermissionsDescription describePermissions(UriInfo ui) {
-		Map<String, Permission> perm = support.getPermissionMap(context);
-		return new PermissionsDescription(secure(ui).path("{id}"), perm);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Permission describePermission(String id) {
-		return support.getPermission(context, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Permission setPermission(String id, Permission perm) {
-		support.setPermission(context, id, perm);
-		return support.getPermission(context, id);
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response deletePermission(String id, UriInfo ui) {
-		support.setPermission(context, id, Permission.None);
-		return noContent().build();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public Response makePermission(PermissionDescription desc, UriInfo ui) {
-		support.setPermission(context, desc.userName, desc.permission);
-		return created(secure(ui).path("{user}").build(desc.userName)).build();
-	}
-
-	@Override
-	@CallCounted
-	public Response descriptionOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response ownerOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response credentialsOptions() {
-		return opt("POST", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response credentialOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response trustsOptions() {
-		return opt("POST", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response trustOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-
-	@Override
-	@CallCounted
-	public Response permissionsOptions() {
-		return opt("POST");
-	}
-
-	@Override
-	@CallCounted
-	public Response permissionOptions(String id) {
-		return opt("PUT", "DELETE");
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java b/server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
deleted file mode 100644
index 6c9e8d8..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
+++ /dev/null
@@ -1,97 +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.util.Arrays.asList;
-import static org.taverna.server.master.common.Uri.secure;
-import static org.taverna.server.master.utils.RestUtils.opt;
-
-import java.util.List;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
-
-import org.taverna.server.master.api.OneListenerBean;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.rest.TavernaServerListenersREST;
-import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
-import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * RESTful interface to a single listener attached to a workflow run.
- * 
- * @author Donal Fellows
- */
-abstract class SingleListenerREST implements TavernaServerListenerREST,
-		OneListenerBean {
-	private Listener listen;
-	private TavernaRun run;
-
-	@Override
-	public SingleListenerREST connect(Listener listen, TavernaRun run) {
-		this.listen = listen;
-		this.run = run;
-		return this;
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public String getConfiguration() {
-		return listen.getConfiguration();
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public ListenerDescription getDescription(UriInfo ui) {
-		return new ListenerDescription(listen, secure(ui));
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenersREST.Properties getProperties(UriInfo ui) {
-		return new TavernaServerListenersREST.Properties(secure(ui).path(
-				"{prop}"), listen.listProperties());
-	}
-
-	@Override
-	@CallCounted
-	@PerfLogged
-	public TavernaServerListenersREST.Property getProperty(
-			final String propertyName) throws NoListenerException {
-		List<String> p = asList(listen.listProperties());
-		if (p.contains(propertyName)) {
-			return makePropertyInterface().connect(listen, run, propertyName);
-		}
-		throw new NoListenerException("no such property");
-	}
-
-	protected abstract ListenerPropertyREST makePropertyInterface();
-
-	@Override
-	@CallCounted
-	public Response listenerOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response configurationOptions() {
-		return opt();
-	}
-
-	@Override
-	@CallCounted
-	public Response propertiesOptions() {
-		return opt();
-	}
-}


[23/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-client/src/main/wadl/tavserv.wadl
----------------------------------------------------------------------
diff --git a/taverna-server-client/src/main/wadl/tavserv.wadl b/taverna-server-client/src/main/wadl/tavserv.wadl
new file mode 100644
index 0000000..2ba8fbe
--- /dev/null
+++ b/taverna-server-client/src/main/wadl/tavserv.wadl
@@ -0,0 +1,591 @@
+<application xmlns="http://wadl.dev.java.net/2009/02"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:prefix1="http://ns.taverna.org.uk/2010/xml/server/rest/"
+	xmlns:prefix3="http://ns.taverna.org.uk/2010/xml/server/"
+	xmlns:prefix10="http://ns.taverna.org.uk/2010/port/" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" jxb:version="2.1">
+<grammars>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:admin="http://ns.taverna.org.uk/2010/xml/server/admin/" xmlns:feed="http://ns.taverna.org.uk/2010/xml/server/feed/" xmlns:port="http://ns.taverna.org.uk/2010/port/" xmlns:tns="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts-rest="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts-soap="http://ns.taverna.org.uk/2010/xml/server/soap/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/xml/server/rest/" jxb:version="2.1">
+    <xs:annotation>
+    	<xs:appinfo>
+			<jxb:schemaBindings>
+				<jxb:package name="uk.org.taverna.server.client.rest" />
+			</jxb:schemaBindings>
+    	</xs:appinfo>
+    </xs:annotation>
+    <xs:import namespace="http://ns.taverna.org.uk/2010/xml/server/"/>
+    <xs:import namespace="http://www.w3.org/1999/xlink"/>
+    <xs:element name="capabilities">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" minOccurs="0" name="capability" type="ts:Capability"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="credential" type="ts-rest:Credential"/>
+    <xs:element name="credentials" type="ts-rest:credentialList"/>
+    <xs:element name="directoryContents" type="ts-rest:DirectoryContents"/>
+    <xs:element name="enabledNotificationFabrics">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" minOccurs="0" name="notifier" type="xs:string"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="filesystemOperation" type="ts-rest:FilesystemCreationOperation"/>
+    <xs:element name="listenerDefinition" type="ts-rest:ListenerDefinition"/>
+    <xs:element name="listenerDescription" type="ts-rest:ListenerDescription"/>
+    <xs:element name="listeners">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="ts:VersionedElement">
+                    <xs:sequence>
+                        <xs:element maxOccurs="unbounded" minOccurs="0" name="listener" type="ts-rest:ListenerDescription"/>
+                    </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="mkdir" type="ts-rest:MakeDirectory"/>
+    <xs:element name="permissionUpdate" type="ts-rest:permissionDescription"/>
+    <xs:element name="permissionsDescriptor" type="ts-rest:permissionsDescription"/>
+    <xs:element name="permittedListeners">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" minOccurs="0" name="type" type="xs:string"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="permittedWorkflows">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" minOccurs="0" name="workflow" type="xs:string"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="policyDescription">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="ts:VersionedElement">
+                    <xs:sequence>
+                        <xs:element minOccurs="0" name="runLimit" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="operatingLimit" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="permittedWorkflows" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="permittedListenerTypes" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="enabledNotificationFabrics" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="capabilities" type="ts:Location"/>
+                    </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="properties">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="ts:VersionedElement">
+                    <xs:sequence>
+                        <xs:element maxOccurs="unbounded" minOccurs="0" name="property" type="ts-rest:PropertyDescription"/>
+                    </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="runDescription">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="ts:VersionedElement">
+                    <xs:sequence>
+                        <xs:element minOccurs="0" name="expiry">
+                            <xs:complexType>
+                                <xs:simpleContent>
+                                    <xs:extension base="xs:string">
+                                        <xs:attribute ref="xlink:href"/>
+                                    </xs:extension>
+                                </xs:simpleContent>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element minOccurs="0" name="creationWorkflow" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="createTime" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="startTime" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="finishTime" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="status" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="workingDirectory" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="inputs" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="output" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="securityContext" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="listeners">
+                            <xs:complexType>
+                                <xs:complexContent>
+                                    <xs:extension base="ts:Location">
+                                        <xs:sequence>
+                                            <xs:element maxOccurs="unbounded" minOccurs="0" name="listener" nillable="true" type="ts:Location"/>
+                                        </xs:sequence>
+                                    </xs:extension>
+                                </xs:complexContent>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element minOccurs="0" name="interaction" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="name" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="stdout" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="stderr" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="usage" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="log" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="run-bundle" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="generate-provenance" type="ts:Location"/>
+                    </xs:sequence>
+                    <xs:attribute ref="ts-rest:owner"/>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="runInput" type="ts-rest:InputDescription"/>
+    <xs:element name="runInputs" type="ts-rest:TavernaRunInputs"/>
+    <xs:element name="runList">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" minOccurs="0" name="run" type="ts:TavernaRun"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="securityDescriptor" type="ts-rest:SecurityDescriptor"/>
+    <xs:element name="serverDescription">
+        <xs:complexType>
+            <xs:complexContent>
+                <xs:extension base="ts:VersionedElement">
+                    <xs:sequence>
+                        <xs:element minOccurs="0" name="runs" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="policy" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="feed" type="ts:Location"/>
+                        <xs:element minOccurs="0" name="interactionFeed" type="ts:Location"/>
+                    </xs:sequence>
+                </xs:extension>
+            </xs:complexContent>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="trustedIdentities" type="ts-rest:trustList"/>
+    <xs:element name="upload" type="ts-rest:UploadFile"/>
+    <xs:element name="userPermission" type="ts-rest:linkedPermissionDescription"/>
+    <xs:complexType name="InputDescription">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:choice minOccurs="0">
+                        <xs:element name="file">
+                            <xs:complexType>
+                                <xs:simpleContent>
+                                    <xs:extension base="ts-rest:InputContents"/>
+                                </xs:simpleContent>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="reference">
+                            <xs:complexType>
+                                <xs:simpleContent>
+                                    <xs:extension base="ts-rest:InputContents"/>
+                                </xs:simpleContent>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="value">
+                            <xs:complexType>
+                                <xs:simpleContent>
+                                    <xs:extension base="ts-rest:InputContents"/>
+                                </xs:simpleContent>
+                            </xs:complexType>
+                        </xs:element>
+                    </xs:choice>
+                </xs:sequence>
+                <xs:attribute ref="ts-rest:name"/>
+                <xs:attribute ref="ts-rest:descriptorRef"/>
+                <xs:attribute ref="ts-rest:listDelimiter"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:simpleType name="InputContents">
+        <xs:restriction base="xs:string"/>
+    </xs:simpleType>
+    <xs:complexType name="ListenerDescription">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element minOccurs="0" name="configuration" type="ts:Location"/>
+                    <xs:element minOccurs="0" name="properties">
+                        <xs:complexType>
+                            <xs:sequence>
+                                <xs:element maxOccurs="unbounded" minOccurs="0" name="property" type="ts-rest:PropertyDescription"/>
+                            </xs:sequence>
+                        </xs:complexType>
+                    </xs:element>
+                </xs:sequence>
+                <xs:attribute ref="xlink:href"/>
+                <xs:attribute ref="ts-rest:name"/>
+                <xs:attribute ref="ts-rest:type"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="PropertyDescription">
+        <xs:complexContent>
+            <xs:extension base="ts:Location">
+                <xs:sequence/>
+                <xs:attribute ref="ts-rest:name"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="TavernaRunInputs">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element minOccurs="0" name="expected" type="ts:Location"/>
+                    <xs:element minOccurs="0" name="baclava" type="ts:Location"/>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" name="input" nillable="true" type="ts:Location"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="Credential">
+        <xs:choice>
+            <xs:element ref="ts:keypair"/>
+            <xs:element ref="ts:userpass"/>
+        </xs:choice>
+    </xs:complexType>
+    <xs:complexType name="DirectoryContents">
+        <xs:sequence>
+            <xs:choice maxOccurs="unbounded" minOccurs="0">
+                <xs:element ref="ts:dir"/>
+                <xs:element ref="ts:file"/>
+            </xs:choice>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="FilesystemCreationOperation">
+        <xs:simpleContent>
+            <xs:extension base="xs:base64Binary">
+                <xs:attribute ref="ts-rest:name"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="MakeDirectory">
+        <xs:simpleContent>
+            <xs:extension base="ts-rest:FilesystemCreationOperation"/>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="UploadFile">
+        <xs:simpleContent>
+            <xs:extension base="ts-rest:FilesystemCreationOperation"/>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="permissionsDescription">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" name="permission" type="ts-rest:linkedPermissionDescription"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="linkedPermissionDescription">
+        <xs:complexContent>
+            <xs:extension base="ts:Location">
+                <xs:sequence>
+                    <xs:element minOccurs="0" name="userName" type="xs:string"/>
+                    <xs:element minOccurs="0" name="permission" type="ts:Permission"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="trustList">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" name="trust" type="ts:TrustDescriptor"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="permissionDescription">
+        <xs:sequence>
+            <xs:element minOccurs="0" name="userName" type="xs:string"/>
+            <xs:element minOccurs="0" name="permission" type="ts:Permission"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="SecurityDescriptor">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element minOccurs="0" name="owner" type="xs:string"/>
+                    <xs:element minOccurs="0" name="permissions" type="ts:Location"/>
+                    <xs:element minOccurs="0" name="credentials" type="ts-rest:CredentialCollection"/>
+                    <xs:element minOccurs="0" name="trusts" type="ts-rest:TrustCollection"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="CredentialCollection">
+        <xs:sequence>
+            <xs:element maxOccurs="unbounded" minOccurs="0" ref="ts-rest:credential"/>
+        </xs:sequence>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="TrustCollection">
+        <xs:sequence>
+            <xs:element maxOccurs="unbounded" minOccurs="0" name="trust" type="ts:TrustDescriptor"/>
+        </xs:sequence>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="credentialList">
+        <xs:complexContent>
+            <xs:extension base="ts:VersionedElement">
+                <xs:sequence>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" ref="ts-rest:credential"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="ListenerDefinition">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute ref="ts-rest:type"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:attribute name="descriptorRef" type="xs:anyURI"/>
+    <xs:attribute name="listDelimiter" type="xs:string"/>
+    <xs:attribute name="name" type="xs:string"/>
+    <xs:attribute name="owner" type="xs:string"/>
+    <xs:attribute name="type" type="xs:string"/>
+</xs:schema>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xlink" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://www.w3.org/1999/xlink" jxb:version="2.1">
+    <xs:attribute name="href" type="xs:string"/>
+</xs:schema>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:port="http://ns.taverna.org.uk/2010/port/" xmlns:run="http://ns.taverna.org.uk/2010/run/" xmlns:tns="http://ns.taverna.org.uk/2010/port/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/port/" jxb:version="2.1">
+    <xs:annotation>
+    	<xs:appinfo>
+			<jxb:schemaBindings>
+				<jxb:package name="uk.org.taverna.server.client.generic.port" />
+			</jxb:schemaBindings>
+    	</xs:appinfo>
+    </xs:annotation>
+    <xs:import namespace="http://www.w3.org/1999/xlink"/>
+    <xs:element name="inputDescription" type="port:inputDescription"/>
+    <xs:element name="workflowOutputs" type="port:outputDescription"/>
+    <xs:complexType name="outputDescription">
+        <xs:complexContent>
+            <xs:extension base="port:PortDescription">
+                <xs:sequence>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" name="output" type="port:OutputPort"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType abstract="true" name="PortDescription">
+        <xs:sequence/>
+        <xs:attribute ref="port:workflowId"/>
+        <xs:attribute ref="port:workflowRun"/>
+        <xs:attribute ref="port:workflowRunId"/>
+    </xs:complexType>
+    <xs:complexType name="OutputPort">
+        <xs:complexContent>
+            <xs:extension base="port:Port">
+                <xs:choice>
+                    <xs:element name="value" type="port:LeafValue"/>
+                    <xs:element name="list" type="port:ListValue"/>
+                    <xs:element name="error" type="port:ErrorValue"/>
+                    <xs:element name="absent" type="port:AbsentValue"/>
+                </xs:choice>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="Port">
+        <xs:sequence/>
+        <xs:attribute ref="port:name" use="required"/>
+        <xs:attribute ref="port:depth"/>
+    </xs:complexType>
+    <xs:complexType name="LeafValue">
+        <xs:complexContent>
+            <xs:extension base="port:Value">
+                <xs:sequence/>
+                <xs:attribute ref="port:contentFile"/>
+                <xs:attribute ref="port:contentType"/>
+                <xs:attribute ref="port:contentByteLength"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType abstract="true" name="Value">
+        <xs:sequence/>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:complexType name="ErrorValue">
+        <xs:complexContent>
+            <xs:extension base="port:Value">
+                <xs:sequence/>
+                <xs:attribute ref="port:depth"/>
+                <xs:attribute ref="port:errorFile"/>
+                <xs:attribute ref="port:errorByteLength"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="ListValue">
+        <xs:complexContent>
+            <xs:extension base="port:Value">
+                <xs:sequence>
+                    <xs:choice maxOccurs="unbounded" minOccurs="0">
+                        <xs:element name="value" type="port:LeafValue"/>
+                        <xs:element name="list" type="port:ListValue"/>
+                        <xs:element name="error" type="port:ErrorValue"/>
+                        <xs:element name="absent" type="port:AbsentValue"/>
+                    </xs:choice>
+                </xs:sequence>
+                <xs:attribute ref="port:length"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="AbsentValue">
+        <xs:complexContent>
+            <xs:extension base="port:Value">
+                <xs:sequence/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="inputDescription">
+        <xs:complexContent>
+            <xs:extension base="port:PortDescription">
+                <xs:sequence>
+                    <xs:element maxOccurs="unbounded" minOccurs="0" name="input" type="port:InputPort"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="InputPort">
+        <xs:complexContent>
+            <xs:extension base="port:Port">
+                <xs:sequence/>
+                <xs:attribute ref="xlink:href"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:attribute name="contentByteLength" type="xs:long"/>
+    <xs:attribute name="contentFile" type="xs:string"/>
+    <xs:attribute name="contentType" type="xs:string"/>
+    <xs:attribute name="depth" type="xs:int"/>
+    <xs:attribute name="errorByteLength" type="xs:long"/>
+    <xs:attribute name="errorFile" type="xs:string"/>
+    <xs:attribute name="length" type="xs:int"/>
+    <xs:attribute name="name" type="xs:ID"/>
+    <xs:attribute name="workflowId" type="xs:string"/>
+    <xs:attribute name="workflowRun" type="xs:anyURI"/>
+    <xs:attribute name="workflowRunId" type="xs:string"/>
+</xs:schema>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:admin="http://ns.taverna.org.uk/2010/xml/server/admin/" xmlns:feed="http://ns.taverna.org.uk/2010/xml/server/feed/" xmlns:tns="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts-rest="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts-soap="http://ns.taverna.org.uk/2010/xml/server/soap/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/xml/server/" jxb:version="2.1">
+    <xs:annotation>
+    	<xs:appinfo>
+			<jxb:schemaBindings>
+				<jxb:package name="uk.org.taverna.server.client.generic" />
+			</jxb:schemaBindings>
+    	</xs:appinfo>
+    </xs:annotation>
+    <xs:import namespace="http://www.w3.org/1999/xlink"/>
+    <xs:element name="capability" type="ts:Capability"/>
+    <xs:element name="dir" type="ts:DirectoryReference"/>
+    <xs:element name="file" type="ts:FileReference"/>
+    <xs:element name="keypair" type="ts:KeyPairCredential"/>
+    <xs:element name="runReference" type="ts:TavernaRun"/>
+    <xs:element name="trustedIdentity" type="ts:TrustDescriptor"/>
+    <xs:element name="userpass" type="ts:PasswordCredential"/>
+    <xs:element name="workflow" type="ts:Workflow"/>
+    <xs:complexType abstract="true" name="VersionedElement">
+        <xs:sequence/>
+        <xs:attribute ref="ts:serverVersion"/>
+        <xs:attribute ref="ts:serverRevision"/>
+        <xs:attribute ref="ts:serverBuildTimestamp"/>
+    </xs:complexType>
+    <xs:complexType name="Location">
+        <xs:sequence/>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:complexType name="Capability">
+        <xs:sequence/>
+        <xs:attribute ref="ts:capability"/>
+        <xs:attribute ref="ts:version"/>
+    </xs:complexType>
+    <xs:complexType name="KeyPairCredential">
+        <xs:complexContent>
+            <xs:extension base="ts:CredentialDescriptor">
+                <xs:sequence>
+                    <xs:element name="credentialName" type="xs:string"/>
+                    <xs:element minOccurs="0" name="credentialFile" type="xs:string"/>
+                    <xs:element minOccurs="0" name="fileType" type="xs:string"/>
+                    <xs:element minOccurs="0" name="unlockPassword" type="xs:string"/>
+                    <xs:element minOccurs="0" name="credentialBytes" type="xs:base64Binary"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType abstract="true" name="CredentialDescriptor">
+        <xs:sequence>
+            <xs:element minOccurs="0" name="serviceURI" type="xs:anyURI"/>
+        </xs:sequence>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:complexType name="PasswordCredential">
+        <xs:complexContent>
+            <xs:extension base="ts:CredentialDescriptor">
+                <xs:sequence>
+                    <xs:element name="username" type="xs:string"/>
+                    <xs:element name="password" type="xs:string"/>
+                </xs:sequence>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+    <xs:complexType name="DirectoryEntry">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute ref="xlink:href"/>
+                <xs:attribute ref="ts:name"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="DirectoryReference">
+        <xs:simpleContent>
+            <xs:extension base="ts:DirectoryEntry"/>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="FileReference">
+        <xs:simpleContent>
+            <xs:extension base="ts:DirectoryEntry"/>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="TavernaRun">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute ref="xlink:href"/>
+                <xs:attribute ref="ts:serverVersion"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+    <xs:complexType name="Workflow">
+        <xs:sequence>
+            <xs:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="lax"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType final="extension restriction" name="TrustDescriptor">
+        <xs:sequence>
+            <xs:element minOccurs="0" name="certificateFile" type="xs:string"/>
+            <xs:element minOccurs="0" name="fileType" type="xs:string"/>
+            <xs:element minOccurs="0" name="certificateBytes" type="xs:base64Binary"/>
+            <xs:element maxOccurs="unbounded" minOccurs="0" name="serverName" type="xs:string"/>
+        </xs:sequence>
+        <xs:attribute ref="xlink:href"/>
+    </xs:complexType>
+    <xs:simpleType name="Permission">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="none"/>
+            <xs:enumeration value="read"/>
+            <xs:enumeration value="update"/>
+            <xs:enumeration value="destroy"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:attribute name="capability" type="xs:anyURI"/>
+    <xs:attribute name="name" type="xs:string"/>
+    <xs:attribute name="serverBuildTimestamp" type="xs:string"/>
+    <xs:attribute name="serverRevision" type="xs:string"/>
+    <xs:attribute name="serverVersion" type="xs:string"/>
+    <xs:attribute name="version" type="xs:string"/>
+</xs:schema>
+</grammars><resources base="http://example.com/taverna/rest"><resource path="/"><method name="GET"><doc>Produces the description of the service.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:serverDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the service.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="runs"><method name="GET"><doc>Produces a list of all runs visible to the user.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runList"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the operations on the collection of runs.</doc><response><representation mediaType="application/octet-stream"><
 /representation></response></method><method name="POST"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc><request><representation mediaType="application/vnd.taverna.t2flow+xml" element="prefix3:workflow"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc></representation><representation mediaType="application/xml" element="prefix3:workflow"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Accepts a URL to a workflow to download and run. The URL must be hosted on a publicly-accessible service.</doc><request><representation mediaType="text/uri-list"><doc>Accepts a URL to a workflow to download and run. The URL must be hosted on a publicly-accessible service.</doc></representation></request><response><representation mediaType=
 "application/octet-stream"></representation></response></method></resource><resource path="/policy"><method name="GET"><doc>Describe the parts of this policy.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:policyDescription"></representation><representation mediaType="application/json"></representation></response></method><resource path="/capabilities"><method name="GET"><doc>Gets a description of the capabilities supported by this installation of Taverna Server.</doc><response><representation mediaType="application/xml" element="prefix1:capabilities"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/enabledNotificationFabrics"><method name="GET"><doc>Gets the list of supported, enabled notification fabrics. Each corresponds (approximately) to a protocol, e.g., email.</doc><response><representation mediaType="application/xml" element="prefix1:enabledNotificati
 onFabrics"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/operatingLimit"><method name="GET"><doc>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.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:int"><doc>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.</doc></param></representation></response></method></resource><resource path="/permittedListenerTypes"><method name="GET"><doc>Gets the list of permitted event listener types.</doc><response><representation mediaType="application/xml" element="prefix1:
 permittedListeners"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/permittedWorkflows"><method name="GET"><doc>Gets the list of permitted workflows.</doc><response><representation mediaType="application/xml" element="prefix1:permittedWorkflows"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/runLimit"><method name="GET"><doc>Gets the maximum number of simultaneous runs in any state that the user may create.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:int"><doc>Gets the maximum number of simultaneous runs in any state that the user may create.</doc></param></representation></response></method></resource></resource><resource path="/runs/{runName}"><doc>This represents how a Taverna Server workflow run looks to a RESTful API.</doc><param name="runName" style="template" type="x
 s:string"/><method name="DELETE"><doc>Deletes a workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Describes a workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/createTime"><method name="GET"><doc>Gives the time when the workflow run was first submitted to the server.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was first submitted to the server.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the d
 escription of the run create time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/expiry"><method name="GET"><doc>Gives the time when the workflow run becomes eligible for automatic deletion.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run becomes eligible for automatic deletion.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run expiry.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc></param><
 /representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc></param></representation></response></method></resource><resource path="/finishTime"><method name="GET"><doc>Gives the time when the workflow run was first detected as finished, or an empty string if it has not yet finished (including if it has never started).</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was first detected as finished, or an empty string if it has not yet finished (including if it has never started).</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run finish time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="
 /generate-provenance"><method name="GET"><doc>Whether to create the run bundle for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Whether to create the run bundle for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Whether to create the run bundle for the workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></response></
 method></resource><resource path="/log"><method name="GET"><doc>Return the log for the workflow run.</doc><response><representation mediaType="text/plain"></representation></response></method><method name="OPTIONS"><doc>Return the log for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/name"><method name="GET"><doc>Gives the descriptive name of the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the descriptive name of the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the operations on the run&apos;s descriptive name.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitraril
 y truncated by the implementation.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitrarily truncated by the implementation.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitrarily truncated by the implementation.</doc></param></representation></response></method></resource><resource path="/output"><method name="GET"><doc>Gives the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></repre
 sentation></response></method><method name="GET"><doc>Gives a description of the outputs, as currently understood</doc><request></request><response><representation mediaType="application/xml" element="prefix10:workflowOutputs"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run output.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:st
 ring"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></representation></response></method></resource><resource path="/run-bundle"><method name="GET"><doc>Return the run bundle for the workflow run.</doc><response><representation mediaType="application/vnd.wf4ever.robundle+zip"></representation></response></method><method name="OPTIONS"><doc>Return the run bundle for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/startTime"><method name="GET"><doc>Gives the time when the workflow run was started, or an empty string if the run has not yet started.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was started, or an empty string if the run has not yet started.</doc></param></representation></response></met
 hod><method name="OPTIONS"><doc>Produces the description of the run start time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/status"><method name="GET"><doc>Gives the current status of the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the current status of the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run status.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Attempts to update the status of the workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Attempts to update the status of the workflow run.</doc></param></representation></request><response><representation mediaType="text/pla
 in"></representation></response></method></resource><resource path="/stderr"><method name="GET"><doc>Return the stderr for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Return the stderr for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Return the stderr for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/stdout"><method name="GET"><doc>Return the stdout for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Return the stdout for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Return the stdout for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resour
 ce><resource path="/usage"><method name="GET"><doc>Return the usage record for the workflow run.</doc><response><representation mediaType="application/xml"></representation></response></method><method name="OPTIONS"><doc>Return the usage record for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/workflow"><method name="GET"><doc>Gives the workflow document used to create the workflow run.</doc><response><representation mediaType="application/vnd.taverna.t2flow+xml" element="prefix3:workflow"></representation><representation mediaType="application/xml" element="prefix3:workflow"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run workflow.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/inp
 ut"><doc>This represents how a Taverna Server workflow run&apos;s inputs looks to a RESTful API.</doc><method name="GET"><doc>Describe the sub-URIs of this resource.</doc><response><representation mediaType="application/xml" element="prefix1:runInputs"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run&apos;s inputs&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/baclava"><method name="GET"><doc>Gives the Baclava file describing the inputs, or empty if individual files are used.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the Baclava file describing the inputs, or empty if individual files are used.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the inp
 uts&apos; baclava operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the Baclava file describing the inputs.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the Baclava file describing the inputs.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Sets the Baclava file describing the inputs.</doc></param></representation></response></method></resource><resource path="/expected"><method name="GET"><doc>Describe the expected inputs of this workflow run.</doc><response><representation mediaType="application/xml" element="prefix10:inputDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the expected inputs&apos; operati
 ons.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/input/{name}"><param name="name" style="template" type="xs:string"/><method name="GET"><doc>Gives a description of what is used to supply a particular input.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runInput"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the one input&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the source for a particular input port.</doc><request><representation mediaType="application/xml" element="prefix1:runInput"><doc>Sets the source for a particular input port.</doc></representation><representation mediaType="application/json"><doc>Sets the
  source for a particular input port.</doc></representation></request><response><representation mediaType="application/xml" element="prefix1:runInput"></representation><representation mediaType="application/json"></representation></response></method></resource></resource><resource path="/interaction"><method name="GET"><doc>Get the feed document for this ATOM feed.</doc><response><representation mediaType="application/atom+xml"></representation></response></method><method name="OPTIONS"><doc>Describes what HTTP operations are supported on the feed.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Adds an entry to this ATOM feed.</doc><request><representation mediaType="application/atom+xml"><doc>Adds an entry to this ATOM feed.</doc></representation></request><response><representation mediaType="application/atom+xml"></representation></response></method><resource path="/{id}"><param name="id" style="temp
 late" type="xs:string"/><method name="DELETE"><doc>Deletes an entry from this ATOM feed.</doc><request></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Deletes an entry from this ATOM feed.</doc></param></representation></response></method><method name="GET"><doc>Get the entry with a particular ID within this ATOM feed.</doc><request></request><response><representation mediaType="application/atom+xml"></representation></response></method><method name="OPTIONS"><doc>Describes what HTTP operations are supported on an entry.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource></resource><resource path="/listeners"><doc>This represents all the event listeners attached to a workflow run.</doc><method name="GET"><doc>Get the listeners installed in the workflow run.</doc><request></request><response><representation mediaType="application/xml"
  element="prefix1:listeners"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run listeners&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Add a new event listener to the named workflow run.</doc><request><representation mediaType="application/xml" element="prefix1:listenerDefinition"><doc>Add a new event listener to the named workflow run.</doc></representation><representation mediaType="application/json"><doc>Add a new event listener to the named workflow run.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/{name}"><doc>This represents a single event listener attached to a workflow run.</doc><param name="name" style="template" type="xs:string"/><method name="GET"><doc>Get th
 e description of this listener.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:listenerDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/configuration"><method name="GET"><doc>Get the configuration for the given event listener that is attached to a workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Get the configuration for the given event listener that is attached to a workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s configuration&apos;s operations.</doc><response><representation mediaType="applica
 tion/octet-stream"></representation></response></method></resource><resource path="/properties"><method name="GET"><doc>Get the list of properties supported by a given event listener attached to a workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:properties"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s properties&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/properties/{propertyName}"><doc>This represents a single property attached of an event listener.</doc><param name="propertyName" style="template" type="xs:string"/><method name="GET"><doc>Get the value of the particular property of an event listener attached to a workflow run.</doc><response><representation mediaType="text/plain"><param
  name="result" style="plain" type="xs:string"><doc>Get the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s property&apos;s operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></response><
 /method></resource></resource></resource><resource path="/security"><doc>Manages the security of the workflow run. In general, only the owner of a run may access this resource.</doc><method name="GET"><doc>Gives a description of the security information supported by the workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:securityDescriptor"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run security.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/credentials"><method name="DELETE"><doc>Deletes all credentials.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Gives a list of credentials supplied to this workflow run.</doc><response><representation
  mediaType="application/xml" element="prefix1:credentials"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run credentials&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Creates a new credential.</doc><request><representation mediaType="application/xml" element="prefix1:credential"><doc>Creates a new credential.</doc></representation><representation mediaType="application/json"><doc>Creates a new credential.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/credentials/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes a particular credential.</doc><request></request><response><representation mediaType="application/octet-stre
 am"></representation></response></method><method name="GET"><doc>Describes a particular credential.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:credential"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run credential&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates a particular credential.</doc><request><representation mediaType="application/xml" element="prefix1:credential"><doc>Updates a particular credential.</doc></representation><representation mediaType="application/json"><doc>Updates a particular credential.</doc></representation></request><response><representation mediaType="application/xml" element="prefix1:credential"></representation><representation mediaType="application/json"></represe
 ntation></response></method></resource><resource path="/owner"><method name="GET"><doc>Gives the identity of who owns the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the identity of who owns the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run owner.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/permissions"><method name="GET"><doc>Gives a list of all non-default permissions associated with the enclosing workflow run. By default, nobody has any access at all except for the owner of the run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:permissionsDescriptor"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Pro
 duces the description of the run permissions&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Creates a new assignment of permissions to a particular user.</doc><request><representation mediaType="application/xml" element="prefix1:permissionUpdate"><doc>Creates a new assignment of permissions to a particular user.</doc></representation><representation mediaType="application/json"><doc>Creates a new assignment of permissions to a particular user.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/permissions/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes (by resetting to default) the permissions associated with a particular user.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></
 response></method><method name="GET"><doc>Describes the permission granted to a particular user.</doc><request></request><response><representation mediaType="text/plain"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run permission&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates the permissions granted to a particular user.</doc><request><representation mediaType="text/plain"><doc>Updates the permissions granted to a particular user.</doc></representation></request><response><representation mediaType="text/plain"></representation></response></method></resource><resource path="/trusts"><method name="DELETE"><doc>Deletes all trusted identities.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Gives a list of trust
 ed identities supplied to this workflow run.</doc><response><representation mediaType="application/xml" element="prefix1:trustedIdentities"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run trusted certificates&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Adds a new trusted identity.</doc><request><representation mediaType="application/xml" element="prefix3:trustedIdentity"><doc>Adds a new trusted identity.</doc></representation><representation mediaType="application/json"><doc>Adds a new trusted identity.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/trusts/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes a particu
 lar trusted identity.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Describes a particular trusted identity.</doc><request></request><response><representation mediaType="application/xml" element="prefix3:trustedIdentity"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run trusted certificate&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates a particular trusted identity.</doc><request><representation mediaType="application/xml" element="prefix3:trustedIdentity"><doc>Updates a particular trusted identity.</doc></representation><representation mediaType="application/json"><doc>Updates a particular trusted identity.</doc></representation></request><respo
 nse><representation mediaType="application/xml" element="prefix3:trustedIdentity"></representation><representation mediaType="application/json"></representation></response></method></resource></resource><resource path="/wd"><doc>Representation of how a workflow run&apos;s working directory tree looks.</doc><method name="GET"><doc>Describes the working directory of the workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:directoryContents"></representation><representation mediaType="application/json"></representation></response></method><resource path="/{path:(.*)}"><param name="path" style="template" repeating="true"/><method name="POST"><doc>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.</doc><request><representation mediaType="text/uri-list"><doc>Creates or updates a file in a particular location beneath the working directory o
 f the workflow run with the contents of a publicly readable URL.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="PUT"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc><request><representation mediaType="application/octet-stream"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc></representation><representation mediaType="*/*"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/{path:.*}"><param name="path" style="template" repeating="true"/><method 
 name="DELETE"><doc>Deletes a file or directory that is in or below the working directory of a workflow run.</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the files/directories&apos; baclava operations.</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="POST"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or creates or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc><request><representation mediaType="application/xml" element="prefix1:filesystemOperation"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or create
 s or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc></representation><representation mediaType="application/json"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or creates or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/{path:.+}"><param name="path" style="template" repeating="true"/><method name="GET"><doc>Gives a description of the named entity in or beneath the working directory of the workflow run (either a Directory or File).</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation><representation mediaTyp
 e="application/octet-stream"></representation><representation mediaType="application/zip"></representation><representation mediaType="*/*"></representation></response></method></resource></resource></resource></resource></resources></application>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-distribution/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-distribution/pom.xml b/taverna-server-distribution/pom.xml
new file mode 100644
index 0000000..8939dbf
--- /dev/null
+++ b/taverna-server-distribution/pom.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-distribution</artifactId>
+	<name>Apache Taverna Server Distribution Packaging</name>
+	<packaging>pom</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.parent.version}</groupId>
+			<artifactId>taverna-server-webapp</artifactId>
+			<version>${project.parent.version}</version>
+			<type>war</type>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<finalName>TavernaServer-${project.parent.version}</finalName>
+					<descriptors>
+						<descriptor>src/assemble/dist.xml</descriptor>
+					</descriptors>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-t2server-distribution</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>default</id>
+						<phase>none</phase>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>default</id>
+						<phase>none</phase>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	<reporting>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-project-info-reports-plugin</artifactId>
+				<version>2.4</version>
+				<reportSets>
+					<reportSet>
+						<reports>
+							<!-- Only generate the index, nothing else. -->
+							<report>index</report>
+						</reports>
+					</reportSet>
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>2.8</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-changelog-plugin</artifactId>
+				<version>2.2</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-changes-plugin</artifactId>
+				<version>2.6</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-checkstyle-plugin</artifactId>
+				<version>2.7</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-pmd-plugin</artifactId>
+				<version>2.5</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-report-plugin</artifactId>
+				<version>2.9</version>
+				<reportSets>
+					<reportSet />
+				</reportSets>
+			</plugin>
+		</plugins>
+	</reporting>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-distribution/src/assemble/dist.xml
----------------------------------------------------------------------
diff --git a/taverna-server-distribution/src/assemble/dist.xml b/taverna-server-distribution/src/assemble/dist.xml
new file mode 100644
index 0000000..a77883c
--- /dev/null
+++ b/taverna-server-distribution/src/assemble/dist.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+	<id>distribution</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+<!-- 
+	<dependencySets>
+		<dependencySet>
+			<useTransitiveDependencies>false</useTransitiveDependencies>
+			<useProjectArtifact>false</useProjectArtifact>
+			<unpack>false</unpack>
+			<scope>runtime</scope>
+			<fileMode>0644</fileMode>
+		</dependencySet>
+	</dependencySets>
+	<fileSets>
+		<fileSet>
+			<includes>
+				<include>*.html</include>
+				<include>*.xml</include>
+				<include>*.txt</include>
+				<include>*.pdf</include>
+			</includes>
+			<excludes>
+				<exclude>pom.xml</exclude>
+			</excludes>
+		</fileSet>
+	</fileSets>
+-->
+	<fileSets>
+		<fileSet>
+			<directory>${project.parent.basedir}</directory>
+			<includes>
+				<include>*.xml</include>
+				<include>*.txt</include>
+				<include>*.pdf</include>
+			</includes>
+			<excludes>
+				<exclude>pom.xml</exclude>
+			</excludes>
+			<fileMode>0644</fileMode>
+			<outputDirectory>.</outputDirectory>
+		</fileSet>
+		<fileSet>
+			<directory>${project.parent.basedir}/server-webapp/target</directory>
+			<includes>
+				<include>*.war</include>
+			</includes>
+			<outputDirectory>.</outputDirectory>
+			<fileMode>0644</fileMode>
+		</fileSet>
+	</fileSets>
+<!-- 
+	<moduleSets>
+		<moduleSet>
+			<includes>
+				<include>uk.org.taverna.server:server</include>
+			</includes>
+			<sources>
+				<fileSets>
+					<fileSet>
+						<includes>
+							<include>*.html</include>
+							<include>*.txt</include>
+						</includes>
+					</fileSet>
+				</fileSets>
+			</sources>
+		</moduleSet>
+		<moduleSet>
+			<includes>
+				<include>uk.org.taverna.server:server-webapp</include>
+			</includes>
+			<binaries />
+		</moduleSet>
+	</moduleSets>
+-->
+</assembly>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-execution-delegate/pom.xml b/taverna-server-execution-delegate/pom.xml
new file mode 100644
index 0000000..59c8aff
--- /dev/null
+++ b/taverna-server-execution-delegate/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-execution-delegate</artifactId>
+	<packaging>bundle</packaging>
+	<name>Apache Taverna Server Reporting Probe</name>
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.taverna.engine</groupId>
+			<artifactId>taverna-execution-api</artifactId>
+			<version>${taverna.engine.version}</version>
+			<type>bundle</type>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java b/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
new file mode 100644
index 0000000..7ea9998
--- /dev/null
+++ b/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
@@ -0,0 +1,172 @@
+package org.taverna.server.execution_delegate;
+
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Map;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.taverna.server.execution_delegate.RemoteExecution.ProcessorReportDocument.Property;
+
+import uk.org.taverna.platform.data.api.Data;
+import uk.org.taverna.platform.data.api.DataLocation;
+import uk.org.taverna.platform.execution.api.Execution;
+import uk.org.taverna.platform.report.ActivityReport;
+import uk.org.taverna.platform.report.ProcessorReport;
+import uk.org.taverna.platform.report.StatusReport;
+import uk.org.taverna.platform.report.WorkflowReport;
+import uk.org.taverna.scufl2.api.common.AbstractNamed;
+
+public class ExecutionDelegate extends UnicastRemoteObject implements
+		RemoteExecution {
+	private Execution delegated;
+	private DatatypeFactory dtf;
+
+	public ExecutionDelegate(Execution execution) throws RemoteException,
+			DatatypeConfigurationException {
+		super();
+		delegated = execution;
+		dtf = DatatypeFactory.newInstance();
+	}
+
+	@Override
+	public String getID() {
+		return delegated.getID();
+	}
+
+	@Override
+	public void delete() {
+		delegated.delete();
+	}
+
+	@Override
+	public void start() {
+		delegated.start();
+	}
+
+	@Override
+	public void pause() {
+		delegated.pause();
+	}
+
+	@Override
+	public void resume() {
+		delegated.resume();
+	}
+
+	@Override
+	public void cancel() {
+		delegated.cancel();
+	}
+
+	private XMLGregorianCalendar date(Date d) {
+		if (d == null)
+			return null;
+		GregorianCalendar c = new GregorianCalendar();
+		c.setTime(d);
+		return dtf.newXMLGregorianCalendar(c);
+	}
+
+	private <R extends ReportDocument, T extends AbstractNamed> R init(
+			R snapshot, StatusReport<T, ?, ?> report) {
+		snapshot.created = date(report.getCreatedDate());
+		snapshot.completed = date(report.getCompletedDate());
+		snapshot.cancelled = date(report.getCancelledDate());
+		snapshot.failed = date(report.getFailedDate());
+		snapshot.started = date(report.getStartedDate());
+		for (Date d : report.getPausedDates())
+			snapshot.paused.add(date(d));
+		for (Date d : report.getResumedDates())
+			snapshot.resumed.add(date(d));
+		snapshot.subject = report.getSubject().getName();
+		snapshot.state = report.getState().toString();
+		return snapshot;
+	}
+
+	private WorkflowReportDocument getReport(WorkflowReport report) {
+		WorkflowReportDocument snapshot = init(new WorkflowReportDocument(),
+				report);
+		for (ProcessorReport pr : report.getChildReports())
+			snapshot.processor.add(getReport(pr));
+		initMap(snapshot.inputs, report.getInputs());
+		initMap(snapshot.outputs, report.getOutputs());
+		return snapshot;
+	}
+
+	private void initMap(ArrayList<PortMapping> snapshot, Map<String, ?> report) {
+		for (String port : report.keySet())
+			snapshot.add(data(port, report.get(port)));
+	}
+
+	private static final String DEFAULT_PROPERTY_STRING = "";
+
+	private PortMapping data(String name, Object o) {
+		String loc;
+		if (o instanceof DataLocation) {
+			DataLocation d = (DataLocation) o;
+			loc = d.getDataServiceURI() + "#" + d.getDataID();
+		} else {
+			Data d = (Data) o;
+			loc = null;
+			if (d.hasReferences()) {
+				try {
+					loc = d.getReferences().iterator().next().getURI()
+							.toString();
+				} catch (Exception e) {
+				}
+			}
+			if (loc == null) {
+				DataLocation dl = d.getDataService().getDataLocation(d);
+				loc = dl.getDataServiceURI() + "#" + dl.getDataID();
+			}
+		}
+		return new PortMapping(name, URI.create(loc));
+	}
+
+	private ProcessorReportDocument getReport(ProcessorReport report) {
+		ProcessorReportDocument snapshot = init(new ProcessorReportDocument(),
+				report);
+		for (ActivityReport pr : report.getChildReports())
+			snapshot.activity.add(getReport(pr));
+		snapshot.jobsQueued = report.getJobsStarted();
+		snapshot.jobsStarted = report.getJobsStarted();
+		snapshot.jobsCompleted = report.getJobsCompleted();
+		snapshot.jobsErrored = report.getJobsCompletedWithErrors();
+		for (String key : report.getPropertyKeys()) {
+			Object value = report.getProperty(key);
+			if (value instanceof String || value instanceof Number)
+				snapshot.properties.add(new Property(key, value.toString()));
+			else
+				snapshot.properties.add(new Property(key,
+						DEFAULT_PROPERTY_STRING));
+		}
+		return snapshot;
+	}
+
+	private ActivityReportDocument getReport(ActivityReport report) {
+		ActivityReportDocument snapshot = init(new ActivityReportDocument(),
+				report);
+		for (WorkflowReport pr : report.getChildReports())
+			snapshot.workflow.add(getReport(pr));
+		initMap(snapshot.inputs, report.getInputs());
+		initMap(snapshot.outputs, report.getOutputs());
+		return snapshot;
+	}
+
+	@Override
+	public WorkflowReportDocument getWorkflowReport() {
+		return getReport(delegated.getWorkflowReport());
+	}
+}
+
+// ExecutionDelegate.java:[96,2]
+// initMap(java.util.ArrayList<org.taverna.server.execution_delegate.RemoteExecution.PortMapping>,java.util.Map<java.lang.String,uk.org.taverna.platform.data.api.Data>)
+// in org.taverna.server.execution_delegate.ExecutionDelegate cannot be applied
+// to
+// (java.util.ArrayList<org.taverna.server.execution_delegate.RemoteExecution.PortMapping>,java.util.Map<java.lang.String,uk.org.taverna.platform.data.api.DataLocation>)

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
----------------------------------------------------------------------
diff --git a/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java b/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
new file mode 100644
index 0000000..b8510df
--- /dev/null
+++ b/taverna-server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
@@ -0,0 +1,188 @@
+package org.taverna.server.execution_delegate;
+
+import static javax.xml.bind.annotation.XmlAccessType.NONE;
+
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessorType;
+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.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+/**
+ * Interface for a single execution of a Taverna workflow in a remote process.
+ * 
+ * @author David Withers
+ */
+public interface RemoteExecution extends Remote {
+
+	/**
+	 * Returns the identifier for this execution.
+	 * 
+	 * @return the identifier for this execution
+	 */
+	String getID() throws RemoteException;
+
+	/**
+	 * Returns the <code>WorkflowReport</code> for the execution.
+	 * 
+	 * @return the <code>WorkflowReport</code> for the execution
+	 */
+	WorkflowReportDocument getWorkflowReport() throws RemoteException;
+
+	/**
+	 * Deletes the execution.
+	 */
+	void delete() throws RemoteException;
+
+	/**
+	 * Starts the execution.
+	 */
+	void start() throws RemoteException;
+
+	/**
+	 * Pauses the execution.
+	 */
+	void pause() throws RemoteException;
+
+	/**
+	 * Resumes a paused execution.
+	 */
+	void resume() throws RemoteException;
+
+	/**
+	 * Cancels the execution.
+	 */
+	void cancel() throws RemoteException;
+
+	@XmlType(name = "Report", propOrder = { "state", "created", "started",
+			"completed", "failed", "cancelled", "paused", "resumed" })
+	@XmlSeeAlso({ WorkflowReportDocument.class, ProcessorReportDocument.class,
+			ActivityReportDocument.class })
+	@XmlAccessorType(NONE)
+	public static abstract class ReportDocument {
+		@XmlAttribute
+		public String subject;
+		@XmlElement
+		public String state;
+		@XmlElement(required = true)
+		@XmlSchemaType(name = "dateTime")
+		public XMLGregorianCalendar created;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public XMLGregorianCalendar started;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public XMLGregorianCalendar completed;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public XMLGregorianCalendar failed;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public XMLGregorianCalendar cancelled;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public List<XMLGregorianCalendar> paused;
+		@XmlElement
+		@XmlSchemaType(name = "dateTime")
+		public List<XMLGregorianCalendar> resumed;
+	}
+
+	@XmlType(name = "WorkflowReport", propOrder = { "processor", "inputs",
+			"outputs" })
+	@XmlRootElement(name = "workflowReport")
+	@XmlAccessorType(NONE)
+	public static class WorkflowReportDocument extends ReportDocument {
+		@XmlElement(name = "processor")
+		public ArrayList<ProcessorReportDocument> processor = new ArrayList<ProcessorReportDocument>();
+		@XmlElement(name = "input")
+		public ArrayList<PortMapping> inputs = new ArrayList<PortMapping>();
+		@XmlElement(name = "output")
+		public ArrayList<PortMapping> outputs = new ArrayList<PortMapping>();
+	}
+
+	@XmlType(name = "ProcessorReport", propOrder = { "jobsQueued",
+			"jobsStarted", "jobsCompleted", "jobsErrored", "properties",
+			"activity" })
+	@XmlAccessorType(NONE)
+	public static class ProcessorReportDocument extends ReportDocument {
+		@XmlElement(name = "jobsQueued", required = true)
+		public int jobsQueued;
+		@XmlElement(name = "jobsStarted", required = true)
+		public int jobsStarted;
+		@XmlElement(name = "jobsCompleted", required = true)
+		public int jobsCompleted;
+		@XmlElement(name = "jobsErrored", required = true)
+		public int jobsErrored;
+		@XmlElement(name = "property")
+		@XmlElementWrapper(name = "properties")
+		public ArrayList<Property> properties = new ArrayList<Property>();
+		@XmlElement(name = "activity")
+		public ArrayList<ActivityReportDocument> activity = new ArrayList<ActivityReportDocument>();
+
+		@XmlType(name = "ProcessorProperty")
+		@XmlAccessorType(NONE)
+		public static class Property {
+			@XmlAttribute(name = "key", required = true)
+			String key;
+			@XmlValue
+			String value;
+
+			public Property() {
+			}
+
+			public String getKey() {
+				return key;
+			}
+
+			public String getValue() {
+				return value;
+			}
+
+			Property(String key, String value) {
+				this.key = key;
+				this.value = value;
+			}
+		}
+	}
+
+	@XmlType(name = "ActivityReport", propOrder = { "workflow", "inputs",
+			"outputs" })
+	@XmlAccessorType(NONE)
+	public static class ActivityReportDocument extends ReportDocument {
+		@XmlElement(name = "workflow")
+		public ArrayList<WorkflowReportDocument> workflow = new ArrayList<WorkflowReportDocument>();
+		@XmlElement(name = "input")
+		public ArrayList<PortMapping> inputs = new ArrayList<PortMapping>();
+		@XmlElement(name = "output")
+		public ArrayList<PortMapping> outputs = new ArrayList<PortMapping>();
+	}
+
+	@XmlType(name = "PortMapping")
+	@XmlAccessorType(NONE)
+	public static class PortMapping {
+		public PortMapping() {
+		}
+
+		PortMapping(String port, URI data) {
+			this.name = port;
+			this.reference = data;
+		}
+
+		@XmlAttribute(name = "name")
+		public String name;
+		@XmlAttribute(name = "ref")
+		@XmlSchemaType(name = "anyURI")
+		public URI reference;
+	}
+}


[19/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
new file mode 100644
index 0000000..0f98da6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServer.java
@@ -0,0 +1,1425 @@
+/*
+ * 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/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
new file mode 100644
index 0000000..ce36bd3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/TavernaServerSupport.java
@@ -0,0 +1,957 @@
+/*
+ * 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;
+	}
+}


[38/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
deleted file mode 100644
index c8d7ef6..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/RateLimitedDispatcher.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.joda.time.DateTime;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-
-/**
- * Rate-limiting support. Some message fabrics simply should not be used to send
- * a lot of messages.
- * 
- * @author Donal Fellows
- */
-public abstract class RateLimitedDispatcher implements MessageDispatcher {
-	/** Pre-configured logger. */
-	protected Log log = LogFactory.getLog("Taverna.Server.Notification");
-	private int cooldownSeconds;
-	private Map<String, DateTime> lastSend = new HashMap<>();
-
-	String valid(String value, String def) {
-		if (value == null || value.trim().isEmpty()
-				|| value.trim().startsWith("${"))
-			return def;
-		else
-			return value.trim();
-	}
-
-	/**
-	 * Set how long must elapse between updates to the status of any particular
-	 * user. Calls before that time are just silently dropped.
-	 * 
-	 * @param cooldownSeconds
-	 *            Time to elapse, in seconds.
-	 */
-	public void setCooldownSeconds(int cooldownSeconds) {
-		this.cooldownSeconds = cooldownSeconds;
-	}
-
-	/**
-	 * Test whether the rate limiter allows the given user to send a message.
-	 * 
-	 * @param who
-	 *            Who wants to send the message?
-	 * @return <tt>true</tt> iff they are permitted.
-	 */
-	protected boolean isSendAllowed(String who) {
-		DateTime now = new DateTime();
-		synchronized (lastSend) {
-			DateTime last = lastSend.get(who);
-			if (last != null) {
-				if (!now.isAfter(last.plusSeconds(cooldownSeconds)))
-					return false;
-			}
-			lastSend.put(who, now);
-		}
-		return true;
-	}
-
-	@Override
-	public void dispatch(TavernaRun ignored, String messageSubject,
-			String messageContent, String target) throws Exception {
-		if (isSendAllowed(target))
-			dispatch(messageSubject, messageContent, target);
-	}
-
-	/**
-	 * Dispatch a message to a recipient that doesn't care what produced it.
-	 * 
-	 * @param messageSubject
-	 *            The subject of the message to send.
-	 * @param messageContent
-	 *            The plain-text content of the message to send.
-	 * @param target
-	 *            A description of where it is to go.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	public abstract void dispatch(String messageSubject, String messageContent,
-			String target) throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
deleted file mode 100644
index 5553141..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/SMSDispatcher.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification;
-
-import static org.taverna.server.master.defaults.Default.SMS_GATEWAY_URL;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.message.BasicNameValuePair;
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Dispatch termination messages via SMS.
- * 
- * @author Donal Fellows
- */
-public class SMSDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "sms";
-	}
-
-	private CloseableHttpClient client;
-	private URI service;
-	private String user = "", pass = "";
-	private String usernameField = "username", passwordField = "password",
-			destinationField = "to", messageField = "text";
-
-	/**
-	 * @param usernameField
-	 *            The name of the field that conveys the sending username; this
-	 *            is the <i>server</i>'s identity.
-	 */
-	@Required
-	public void setUsernameField(String usernameField) {
-		this.usernameField = usernameField;
-	}
-
-	/**
-	 * @param passwordField
-	 *            The field holding the password to authenticate the server to
-	 *            the SMS gateway.
-	 */
-	@Required
-	public void setPasswordField(String passwordField) {
-		this.passwordField = passwordField;
-	}
-
-	/**
-	 * @param destinationField
-	 *            The field holding the number to send the SMS to.
-	 */
-	@Required
-	public void setDestinationField(String destinationField) {
-		this.destinationField = destinationField;
-	}
-
-	/**
-	 * @param messageField
-	 *            The field holding the plain-text message to send.
-	 */
-	@Required
-	public void setMessageField(String messageField) {
-		this.messageField = messageField;
-	}
-
-	public void setService(String serviceURL) {
-		String s = valid(serviceURL, "");
-		if (s.isEmpty()) {
-			log.warn("did not get sms.service from servlet config; using default ("
-					+ SMS_GATEWAY_URL + ")");
-			s = SMS_GATEWAY_URL;
-		}
-		try {
-			service = new URI(s);
-		} catch (URISyntaxException e) {
-			service = null;
-		}
-	}
-
-	public void setUser(String user) {
-		this.user = valid(user, "");
-	}
-
-	public void setPassword(String pass) {
-		this.pass = valid(pass, "");
-	}
-
-	@PostConstruct
-	void init() {
-		client = HttpClientBuilder.create().build();
-	}
-
-	@PreDestroy
-	void close() throws IOException {
-		try {
-			if (client != null)
-				client.close();
-		} finally {
-			client = null;
-		}
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return service != null && !user.isEmpty() && !pass.isEmpty();
-	}
-
-	@Override
-	public void dispatch(String messageSubject, String messageContent,
-			String targetParameter) throws Exception {
-		// Sanity check
-		if (!targetParameter.matches("[^0-9]+"))
-			throw new Exception("invalid phone number");
-
-		if (!isSendAllowed("anyone"))
-			return;
-
-		// Build the message to send
-		List<NameValuePair> params = new ArrayList<>();
-		params.add(new BasicNameValuePair(usernameField, user));
-		params.add(new BasicNameValuePair(passwordField, pass));
-		params.add(new BasicNameValuePair(destinationField, targetParameter));
-		params.add(new BasicNameValuePair(messageField, messageContent));
-
-		// Send the message
-		HttpPost post = new HttpPost(service);
-		post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
-		HttpResponse response = client.execute(post);
-
-		// Log the response
-		HttpEntity entity = response.getEntity();
-		if (entity != null)
-			try (BufferedReader e = new BufferedReader(new InputStreamReader(
-					entity.getContent()))) {
-				log.info(e.readLine());
-			}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java b/server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
deleted file mode 100644
index 8ee4815..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/TwitterDispatcher.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification;
-
-import java.util.Properties;
-
-import twitter4j.Twitter;
-import twitter4j.TwitterFactory;
-import twitter4j.conf.Configuration;
-import twitter4j.conf.PropertyConfiguration;
-import twitter4j.auth.AuthorizationFactory;
-
-/**
- * Super simple-minded twitter dispatcher. You need to tell it your consumer key
- * and secret as part of the connection parameters, for example via a dispatcher
- * URN of "<tt>twitter:fred:bloggs</tt>" where <tt>fred</tt> is the key and
- * <tt>bloggs</tt> is the secret.
- * 
- * @author Donal Fellows
- */
-public class TwitterDispatcher extends RateLimitedDispatcher {
-	@Override
-	public String getName() {
-		return "twitter";
-	}
-
-	public static final int MAX_MESSAGE_LENGTH = 140;
-	public static final char ELLIPSIS = '\u2026';
-
-	private String token = "";
-	private String secret = "";
-
-	public void setAccessToken(String token) {
-		this.token = valid(token, "");
-	}
-
-	public void setAccessSecret(String secret) {
-		this.secret = valid(secret, "");
-	}
-
-	private Properties getConfig() throws NotConfiguredException {
-		if (token.isEmpty() || secret.isEmpty())
-			throw new NotConfiguredException();
-		Properties p = new Properties();
-		p.setProperty(ACCESS_TOKEN_PROP, token);
-		p.setProperty(ACCESS_SECRET_PROP, secret);
-		return p;
-	}
-
-	public static final String ACCESS_TOKEN_PROP = "oauth.accessToken";
-	public static final String ACCESS_SECRET_PROP = "oauth.accessTokenSecret";
-
-	private Twitter getTwitter(String key, String secret) throws Exception {
-		if (key.isEmpty() || secret.isEmpty())
-			throw new NoCredentialsException();
-
-		Properties p = getConfig();
-		p.setProperty("oauth.consumerKey", key);
-		p.setProperty("oauth.consumerSecret", secret);
-
-		Configuration config = new PropertyConfiguration(p);
-		TwitterFactory factory = new TwitterFactory(config);
-		Twitter t = factory.getInstance(AuthorizationFactory
-				.getInstance(config));
-		// Verify that we can connect!
-		t.getOAuthAccessToken();
-		return t;
-	}
-
-	// TODO: Get secret from credential manager
-	@Override
-	public void dispatch(String messageSubject, String messageContent,
-			String targetParameter) throws Exception {
-		// messageSubject ignored
-		String[] target = targetParameter.split(":", 2);
-		if (target == null || target.length != 2)
-			throw new Exception("missing consumer key or secret");
-		String who = target[0];
-		if (!isSendAllowed(who))
-			return;
-		Twitter twitter = getTwitter(who, target[1]);
-
-		if (messageContent.length() > MAX_MESSAGE_LENGTH)
-			messageContent = messageContent
-					.substring(0, MAX_MESSAGE_LENGTH - 1) + ELLIPSIS;
-		twitter.updateStatus(messageContent);
-	}
-
-	@Override
-	public boolean isAvailable() {
-		try {
-			// Try to create the configuration and push it through as far as
-			// confirming that we can build an access object (even if it isn't
-			// bound to a user)
-			new TwitterFactory(new PropertyConfiguration(getConfig()))
-					.getInstance();
-			return true;
-		} catch (Exception e) {
-			return false;
-		}
-	}
-
-	/**
-	 * Indicates that the dispatcher has not been configured with service
-	 * credentials.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@SuppressWarnings("serial")
-	public static class NotConfiguredException extends Exception {
-		NotConfiguredException() {
-			super("not configured with xAuth key and secret; "
-					+ "dispatch not possible");
-		}
-	}
-
-	/**
-	 * Indicates that the user did not supply their credentials.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@SuppressWarnings("serial")
-	public static class NoCredentialsException extends Exception {
-		NoCredentialsException() {
-			super("no consumer key and secret present; "
-					+ "dispatch not possible");
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java b/server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
deleted file mode 100644
index e5beaeb..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/AtomFeed.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification.atom;
-
-import static java.lang.String.format;
-import static java.util.UUID.randomUUID;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.common.Uri.secure;
-
-import java.net.URI;
-import java.util.Date;
-
-import javax.annotation.security.RolesAllowed;
-import javax.servlet.ServletContext;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.model.Feed;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.web.context.ServletContextAware;
-import org.taverna.server.master.TavernaServerSupport;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.rest.TavernaServerREST.EventFeed;
-import org.taverna.server.master.utils.InvocationCounter.CallCounted;
-
-/**
- * Simple REST handler that allows an Atom feed to be served up of events
- * generated by workflow runs.
- * 
- * @author Donal Fellows
- */
-public class AtomFeed implements EventFeed, UriBuilderFactory,
-		ServletContextAware {
-	/**
-	 * The name of a parameter that states what address we should claim that the
-	 * feed's internally-generated URIs are relative to. If not set, a default
-	 * will be guessed.
-	 */
-	public static final String PREFERRED_URI_PARAM = "taverna.preferredUserUri";
-	private EventDAO eventSource;
-	private TavernaServerSupport support;
-	private URI baseURI;
-	private Abdera abdera;
-	private String feedLanguage = "en";
-	private String uuid = randomUUID().toString();
-
-	@Required
-	public void setEventSource(EventDAO eventSource) {
-		this.eventSource = eventSource;
-	}
-
-	@Required
-	public void setSupport(TavernaServerSupport support) {
-		this.support = support;
-	}
-
-	public void setFeedLanguage(String language) {
-		this.feedLanguage = language;
-	}
-
-	public String getFeedLanguage() {
-		return feedLanguage;
-	}
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		this.abdera = abdera;
-	}
-
-	@Override
-	@CallCounted
-	@RolesAllowed(USER)
-	public Feed getFeed(UriInfo ui) {
-		Feed feed = abdera.getFactory().newFeed();
-		feed.setTitle("events relating to workflow runs").setLanguage(
-				feedLanguage);
-		String user = support.getPrincipal().toString()
-				.replaceAll("[^A-Za-z0-9]+", "");
-		feed.setId(format("urn:taverna-server:%s:%s", uuid, user));
-		org.joda.time.DateTime modification = null;
-		for (Event e : eventSource.getEvents(support.getPrincipal())) {
-			if (modification == null || e.getPublished().isAfter(modification))
-				modification = e.getPublished();
-			feed.addEntry(e.getEntry(abdera, feedLanguage));
-		}
-		if (modification == null)
-			feed.setUpdated(new Date());
-		else
-			feed.setUpdated(modification.toDate());
-		feed.addLink(ui.getAbsolutePath().toASCIIString(), "self");
-		return feed;
-	}
-
-	@Override
-	@CallCounted
-	@RolesAllowed(USER)
-	public Entry getEvent(String id) {
-		return eventSource.getEvent(support.getPrincipal(), id).getEntry(
-				abdera, feedLanguage);
-	}
-
-	@Override
-	public UriBuilder getRunUriBuilder(TavernaRun run) {
-		return secure(fromUri(getBaseUriBuilder().path("runs/{uuid}").build(
-				run.getId())));
-	}
-
-	@Override
-	public UriBuilder getBaseUriBuilder() {
-		return secure(fromUri(baseURI));
-	}
-
-	@Override
-	public String resolve(String uri) {
-		if (uri == null)
-			return null;
-		return secure(baseURI, uri).toString();
-	}
-
-	@Override
-	public void setServletContext(ServletContext servletContext) {
-		String base = servletContext.getInitParameter(PREFERRED_URI_PARAM);
-		if (base == null)
-			base = servletContext.getContextPath() + "/rest";
-		baseURI = URI.create(base);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java b/server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
deleted file mode 100644
index 825029d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/Event.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification.atom;
-
-import static java.util.UUID.randomUUID;
-
-import java.io.Serializable;
-import java.net.URI;
-import java.util.Date;
-
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Index;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Entry;
-import org.joda.time.DateTime;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Parent class of all events that may appear on the feed for a workflow run.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-@PersistenceCapable(schema = "ATOM", table = "EVENTS")
-@Queries({
-		@Query(name = "eventsForUser", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? ORDER BY published DESC", resultClass = String.class),
-		@Query(name = "eventForUserAndId", language = "SQL", value = "SELECT id FROM ATOM.EVENTS WHERE owner = ? AND id = ?", resultClass = String.class),
-		@Query(name = "eventsFromBefore", language = "SQL", value = "SELECT id FROM ATOM.EVENTS where published < ?", resultClass = String.class) })
-public class Event implements Serializable {
-	@Persistent(primaryKey = "true")
-	@Column(length = 48)
-	private String id;
-	@Persistent
-	private String owner;
-	@Persistent
-	@Index
-	private Date published;
-	@Persistent
-	private String message;
-	@Persistent
-	private String title;
-	@Persistent
-	private String link;
-
-	Event() {
-	}
-
-	/**
-	 * Initialise the identity of this event and the point at which it was
-	 * published.
-	 * 
-	 * @param idPrefix
-	 *            A prefix for the identity of this event.
-	 * @param owner
-	 *            Who is the owner of this event.
-	 */
-	Event(String idPrefix, URI workflowLink, UsernamePrincipal owner,
-			String title, String message) {
-		id = idPrefix + "." + randomUUID().toString();
-		published = new Date();
-		this.owner = owner.getName();
-		this.title = title;
-		this.message = message;
-		this.link = workflowLink.toASCIIString();
-	}
-
-	public final String getId() {
-		return id;
-	}
-
-	public final String getOwner() {
-		return owner;
-	}
-
-	public final DateTime getPublished() {
-		return new DateTime(published);
-	}
-
-	public String getMessage() {
-		return message;
-	}
-
-	public String getTitle() {
-		return title;
-	}
-
-	public String getLink() {
-		return link;
-	}
-
-	public Entry getEntry(Abdera abdera, String language) {
-		Entry entry = abdera.getFactory().newEntry();
-		entry.setId(id);
-		entry.setPublished(published);
-		entry.addAuthor(owner).setLanguage(language);
-		entry.setUpdated(published);
-		entry.setTitle(title).setLanguage(language);
-		entry.addLink(link, "related").setTitle("workflow run");
-		entry.setContent(message).setLanguage(language);
-		return entry;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java b/server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
deleted file mode 100644
index 56f25ff..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/EventDAO.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.notification.atom;
-
-import static java.lang.Thread.interrupted;
-import static java.lang.Thread.sleep;
-import static java.util.Arrays.asList;
-
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-
-import javax.annotation.Nonnull;
-import javax.annotation.PreDestroy;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.joda.time.DateTime;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.MessageDispatcher;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The database interface that supports the event feed.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class EventDAO extends JDOSupport<Event> implements MessageDispatcher {
-	public EventDAO() {
-		super(Event.class);
-	}
-
-	@Override
-	public String getName() {
-		return "atom";
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Atom");
-	private UriBuilderFactory ubf;
-	private int expiryAgeDays;
-
-	@Required
-	public void setExpiryAgeDays(int expiryAgeDays) {
-		this.expiryAgeDays = expiryAgeDays;
-	}
-
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory ubf) {
-		this.ubf = ubf;
-	}
-
-	/**
-	 * Get the given user's list of events.
-	 * 
-	 * @param user
-	 *            The identity of the user to get the events for.
-	 * @return A copy of the list of events currently known about.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public List<Event> getEvents(@Nonnull UsernamePrincipal user) {
-		@SuppressWarnings("unchecked")
-		List<String> ids = (List<String>) namedQuery("eventsForUser").execute(
-				user.getName());
-		if (log.isDebugEnabled())
-			log.debug("found " + ids.size() + " events for user " + user);
-
-		List<Event> result = new ArrayList<>();
-		for (String id : ids) {
-			Event event = getById(id);
-			result.add(detach(event));
-		}
-		return result;
-	}
-
-	/**
-	 * Get a particular event.
-	 * 
-	 * @param user
-	 *            The identity of the user to get the event for.
-	 * @param id
-	 *            The handle of the event to look up.
-	 * @return A copy of the event.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public Event getEvent(@Nonnull UsernamePrincipal user, @Nonnull String id) {
-		@SuppressWarnings("unchecked")
-		List<String> ids = (List<String>) namedQuery("eventForUserAndId")
-				.execute(user.getName(), id);
-		if (log.isDebugEnabled())
-			log.debug("found " + ids.size() + " events for user " + user
-					+ " with id = " + id);
-
-		if (ids.size() != 1)
-			throw new IllegalArgumentException("no such id");
-		return detach(getById(ids.get(0)));
-	}
-
-	/**
-	 * Delete a particular event.
-	 * 
-	 * @param id
-	 *            The identifier of the event to delete.
-	 */
-	@WithinSingleTransaction
-	public void deleteEventById(@Nonnull String id) {
-		delete(getById(id));
-	}
-
-	/**
-	 * Delete all events that have expired.
-	 */
-	@WithinSingleTransaction
-	public void deleteExpiredEvents() {
-		Date death = new DateTime().plusDays(-expiryAgeDays).toDate();
-		death = new Timestamp(death.getTime()); // UGLY SQL HACK
-
-		@SuppressWarnings("unchecked")
-		List<String> ids = (List<String>) namedQuery("eventsFromBefore")
-				.execute(death);
-		if (log.isDebugEnabled() && !ids.isEmpty())
-			log.debug("found " + ids.size()
-					+ " events to be squelched (older than " + death + ")");
-
-		for (String id : ids)
-			delete(getById(id));
-	}
-
-	@Override
-	public boolean isAvailable() {
-		return true;
-	}
-
-	private BlockingQueue<Event> insertQueue = new ArrayBlockingQueue<>(16);
-
-	@Override
-	public void dispatch(TavernaRun originator, String messageSubject,
-			String messageContent, String targetParameter) throws Exception {
-		insertQueue.put(new Event("finish", ubf.getRunUriBuilder(originator)
-				.build(), originator.getSecurityContext().getOwner(),
-				messageSubject, messageContent));
-	}
-
-	public void started(TavernaRun originator, String messageSubject,
-			String messageContent) throws InterruptedException {
-		insertQueue.put(new Event("start", ubf.getRunUriBuilder(originator)
-				.build(), originator.getSecurityContext().getOwner(),
-				messageSubject, messageContent));
-	}
-
-	private Thread eventDaemon;
-	private boolean shuttingDown = false;
-
-	@Required
-	public void setSelf(final EventDAO dao) {
-		eventDaemon = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					while (!shuttingDown && !interrupted()) {
-						transferEvents(dao, new ArrayList<Event>(
-								asList(insertQueue.take())));
-						sleep(5000);
-					}
-				} catch (InterruptedException e) {
-				} finally {
-					transferEvents(dao, new ArrayList<Event>());
-				}
-			}
-		}, "ATOM event daemon");
-		eventDaemon.setContextClassLoader(null);
-		eventDaemon.setDaemon(true);
-		eventDaemon.start();
-	}
-
-	private void transferEvents(EventDAO dao, List<Event> e) {
-		insertQueue.drainTo(e);
-		dao.storeEvents(e);
-	}
-
-	@PreDestroy
-	void stopDaemon() {
-		shuttingDown = true;
-		if (eventDaemon != null)
-			eventDaemon.interrupt();
-	}
-
-	@WithinSingleTransaction
-	protected void storeEvents(List<Event> events) {
-		for (Event e : events)
-			persist(e);
-		log.info("stored " + events.size() + " notification events");
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
deleted file mode 100644
index 9cc592d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/atom/package-info.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the Atom feed implementation within Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = FEED, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.notification.atom;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
deleted file mode 100644
index 979066a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/notification/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * The notification fabric and implementations of notification dispatchers
- * that support subscription.
- */
-package org.taverna.server.master.notification;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/package-info.java
deleted file mode 100644
index 17bfd03..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/package-info.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * The core of the implementation of Taverna Server, including the
- * implementations of the SOAP and REST interfaces.
- */
-package org.taverna.server.master;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java b/server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
deleted file mode 100644
index b0819a5..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/ContentTypes.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_ATOM_XML;
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static javax.ws.rs.core.MediaType.APPLICATION_XML;
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-
-/**
- * Miscellaneous content type constants.
- * 
- * @author Donal Fellows
- */
-interface ContentTypes {
-	static final String URI_LIST = "text/uri-list";
-	static final String ZIP = "application/zip";
-	static final String TEXT = TEXT_PLAIN;
-	static final String XML = APPLICATION_XML;
-	static final String JSON = APPLICATION_JSON;
-	static final String BYTES = APPLICATION_OCTET_STREAM;
-	static final String ATOM = APPLICATION_ATOM_XML;
-	static final String ROBUNDLE = "application/vnd.wf4ever.robundle+zip";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java b/server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
deleted file mode 100644
index e01d1c4..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/DirectoryContents.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.Uri.secure;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.annotation.XmlElementRef;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.DirEntryReference;
-import org.taverna.server.master.interfaces.DirectoryEntry;
-
-/**
- * The result of a RESTful operation to list the contents of a directory. Done
- * with JAXB.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement
-@XmlType(name = "DirectoryContents")
-@XmlSeeAlso(MakeOrUpdateDirEntry.class)
-public class DirectoryContents {
-	/**
-	 * The contents of the directory.
-	 */
-	@XmlElementRef
-	public List<DirEntryReference> contents;
-
-	/**
-	 * Make an empty directory description. Required for JAXB.
-	 */
-	public DirectoryContents() {
-		contents = new ArrayList<>();
-	}
-
-	/**
-	 * Make a directory description.
-	 * 
-	 * @param ui
-	 *            The factory for URIs.
-	 * @param collection
-	 *            The real directory contents that we are to describe.
-	 */
-	public DirectoryContents(UriInfo ui, Collection<DirectoryEntry> collection) {
-		contents = new ArrayList<>();
-		UriBuilder ub = secure(ui).path("{filename}");
-		for (DirectoryEntry e : collection)
-			contents.add(DirEntryReference.newInstance(ub, e));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java b/server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
deleted file mode 100644
index 74269c1..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/FileSegment.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-import static javax.ws.rs.core.Response.ok;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * Representation of a segment of a file to be read by JAX-RS.
- * 
- * @author Donal Fellows
- */
-public class FileSegment {
-	/** The file to read a segment of. */
-	public final File file;
-	/** The offset of the first byte of the segment to read. */
-	public Integer from;
-	/** The offset of the first byte after the segment to read. */
-	public Integer to;
-
-	/**
-	 * Parse the HTTP Range header and determine what exact range of the file to
-	 * read.
-	 * 
-	 * @param f
-	 *            The file this refers to
-	 * @param range
-	 *            The content of the Range header.
-	 * @throws FilesystemAccessException
-	 *             If we can't determine the length of the file (shouldn't
-	 *             happen).
-	 */
-	public FileSegment(File f, String range) throws FilesystemAccessException {
-		file = f;
-		Matcher m = Pattern.compile("^\\s*bytes=(\\d*)-(\\d*)\\s*$").matcher(
-				range);
-		if (m.matches()) {
-			if (!m.group(1).isEmpty())
-				from = Integer.valueOf(m.group(1));
-			if (!m.group(2).isEmpty())
-				to = Integer.valueOf(m.group(2)) + 1;
-			int size = (int) f.getSize();
-			if (from == null) {
-				from = size - to;
-				to = size;
-			} else if (to == null)
-				to = size;
-			else if (to > size)
-				to = size;
-		}
-	}
-
-	/**
-	 * Convert to a response, as per RFC 2616.
-	 * 
-	 * @param type
-	 *            The expected type of the data.
-	 * @return A JAX-RS response.
-	 */
-	public Response toResponse(MediaType type) {
-		if (from == null && to == null)
-			return ok(file).type(type).build();
-		if (from >= to)
-			return ok("Requested range not satisfiable").status(416).build();
-		return ok(this).status(206).type(type).build();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
deleted file mode 100644
index b9b4718..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/InteractionFeedREST.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-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/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java b/server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
deleted file mode 100644
index 7a072be..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/ListenerDefinition.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-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/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java b/server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
deleted file mode 100644
index 0138f88..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/MakeOrUpdateDirEntry.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-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/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
deleted file mode 100644
index ea2f776..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerDirectoryREST.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-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/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
deleted file mode 100644
index faed19d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerInputREST.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * 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.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/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
deleted file mode 100644
index e9b067e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * 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.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));
-		}
-	}
-}


[07/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/admin.js
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/admin.js b/taverna-server-webapp/src/main/resources/static/admin.js
new file mode 100644
index 0000000..c2c41bf
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/static/admin.js
@@ -0,0 +1,549 @@
+// Wrappers round AJAX calls to simplify *most* of this stuff
+
+/** How to retrieve text asynchronously. */
+function getText(u, done) {
+	$.ajax({
+		type : "GET",
+		url : u,
+		async : true,
+		cache : false,
+		accept : "text/plain",
+		dataType : "text",
+		success : done
+	});
+}
+/** How to retrieve JSON asynchronously. */
+function getJSON(u, done) {
+	$.ajax({
+		type : "GET",
+		url : u,
+		async : true,
+		cache : false,
+		dataType : "json",
+		accept : "application/json",
+		success : done
+	});
+}
+/** How to send a PUT of text asynchronously. */
+function putText(u, val, done) {
+	$.ajax({
+		type : "PUT",
+		url : u,
+		async : false,
+		cache : false,
+		data : val,
+		contentType : "text/plain",
+		dataType : "text",
+		processData : false,
+		success : done,
+		error : function(jqXHR, textStatus, errorThrown) {
+			alert(errorThrown);
+		}
+	});
+}
+/** How to send a PUT of XML asynchronously. */
+function putXML(u, xml, done) {
+	$.ajax({
+		type : "PUT",
+		url : u,
+		async : false,
+		cache : false,
+		contentType : "application/xml",
+		data : new XMLSerializer().serializeToString(xml),
+		success : done,
+		error : function(jqXHR, textStatus, errorThrown) {
+			alert(errorThrown);
+		}
+	});
+}
+/** How to send a POST of XML asynchronously. */
+function postXML(u, xml, done) {
+	$.ajax({
+		type : "POST",
+		url : u,
+		async : false,
+		cache : false,
+		contentType : "application/xml",
+		data : new XMLSerializer().serializeToString(xml),
+		success : done,
+		error : function(jqXHR, textStatus, errorThrown) {
+			alert(errorThrown);
+		}
+	});
+}
+/** How to send a DELETE asynchronously. */
+function deleteUrl(u, done) {
+	$.ajax({
+		type : "DELETE",
+		url : u,
+		async : true,
+		cache : false,
+		success : done,
+		error : function(jqXHR, textStatus, errorThrown) {
+			alert(errorThrown);
+		}
+	});
+}
+
+/** Locates a URL with respect to the administrative REST interface. */
+function where(tail) {
+	return $("#admin")[0].href + "/" + tail;
+}
+
+// Make an XML element structure
+// Derived from hack on Stack Overflow, but with extra tinkering
+/** Function called to create a node in an XML structure. */
+var Node;
+/** Function called to create nodes in an XML structure from an array. */
+var NodeAll;
+(function() {
+	var doc = document.implementation.createDocument(null, null, null);
+	var adminNS = "http://ns.taverna.org.uk/2010/xml/server/admin/";
+	Node = function() {
+		var node = doc.createElementNS(adminNS, arguments[0]), child;
+		for ( var i = 1; i < arguments.length; i++) {
+			child = arguments[i];
+			if (child == undefined)
+				continue;
+			if (typeof child != 'object')
+				child = doc.createTextNode(child.toString());
+			node.appendChild(child);
+		}
+		return node;
+	};
+	NodeAll = function(wrapperElem, wrappedElem, elements) {
+		var node = doc.createElementNS(adminNS, wrapperElem);
+		for ( var i = 0; i < elements.length; i++) {
+			var child = doc.createElementNS(adminNS, wrappedElem);
+			var text = doc.createTextNode(elements[i]);
+			child.appendChild(text);
+			node.appendChild(child);
+		}
+		return node;
+	};
+})();
+
+/** The IDs of boolean-coupled buttons. */
+var buttonlist = [ "allowNew", "logFaults", "logWorkflows", "generateProvenance" ];
+/** The IDs of values that track server variables without setting things. */
+var readonlies = [ "invokationCount", "lastExitCode", "runCount", "startupTime", "operatingCount" ];
+/** The IDs of text/numeric-coupled entries. */
+var entries = [ "defaultLifetime", "executeWorkflowScript", "javaBinary",
+		"registrationPollMillis", "registrationWaitSeconds", "registryHost",
+		"registryPort", "runLimit", "runasPasswordFile", "serverForkerJar",
+		"serverWorkerJar", "usageRecordDumpFile", "operatingLimit",
+		"registryJar" ];
+/** Cached information about users. */
+var userinfo = [];
+/** Extra arguments to pass to the runtime. */
+var extraAry = [];
+
+/** How to update the read-only fields; will be called periodically */
+function updateRO() {
+	$.each(readonlies, function(idx, val) {
+		var widget = $("#" + val);
+		getText(where(val), function(data) {
+			widget.html(data);
+		});
+	});
+	getJSON(where("factoryProcessMapping"),
+			function(data) {
+				var ary = data.stringList.string;
+				var tbl = $("#factoryProcessMapping");
+				tbl.html("<tr><th>User<th>ID</tr>");
+				if (ary != undefined)
+					for ( var i = 0; i < ary.length - 1; i += 2)
+						tbl.append("<tr><td>" + ary[i] + "<td>" + ary[i + 1]
+								+ "</tr>");
+			});
+}
+
+/**
+ * Generate a user row with suitable indices, but no content (it will be pushed
+ * into the row later).
+ */
+function userRowHTML(idx) {
+	// USER NAME
+	var content = "<td><span id='username" + idx
+			+ "' title='The login name of the user.'></span></td>";
+	// SYSTEM ID MAPPING
+	content += "<td><input id='userlocal"
+			+ idx
+			+ "' title='The system username to run workflows as, or blank for default.' /></td>";
+	// ENABLED
+	content += "<td><label title='Is this user allowed to log in?' for='useron"
+			+ idx + "'>Enabled</label>" + "<input type='checkbox' id='useron"
+			+ idx + "' /></td>";
+	// ADMIN
+	content += "<td><label title='Is this user an admin (allowed to access this page)?' for='useradmin"
+			+ idx
+			+ "'>Admin</label>"
+			+ "<input type='checkbox' id='useradmin"
+			+ idx + "' /></td>";
+	// SET PASSWORD
+	content += "<td><button title='Set the password for this user.' id='userpass"
+			+ idx + "'>Set Password</button></td>";
+	// DELETE
+	content += "<td><button title='Delete this user. Take care to not delete yourself!' id='userdel"
+			+ idx + "'>Delete</button></td>";
+
+	return "<tr id='usersep" + idx + "' class='userrows'>"
+			+ "<td colspan=6><hr></td></tr>" + "<tr id='userrow" + idx
+			+ "' class='userrows'>" + content + "</tr>";
+}
+
+/** How to get the list of permitted workflows; called on demand */
+function refreshWorkflows() {
+	var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows"), wfref = $("#refreshWorkflows");
+	wfbut.button("disable");
+	wfbut1.button("disable");
+	wfref.button("disable");
+	getJSON(where("permittedWorkflowURIs"), function(data) {
+		var s = "";
+		$.each(data.stringList.string || [], function(idx, str) {
+			s += $.trim(str) + "\n";
+		});
+		wftable.val($.trim(s));
+		wfbut.button("enable");
+		wfbut1.button("enable");
+		wfref.button("enable");
+	});
+}
+/** How to set the list of permitted workflows; called when the user clicks */
+function saveWorkflows() {
+	var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
+	var xml = NodeAll("stringList", "string", wftable.val().split("\n"));
+	wfbut.button("disable");
+	wfbut1.button("disable");
+	putXML(where("permittedWorkflowURIs"), xml, function() {
+		refreshWorkflows();
+	});
+}
+
+/** How to empty the list of permitted workflows; called when the user clicks */
+function emptyWorkflows() {
+        var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
+        var xml = NodeAll("stringList", "string", "");
+        wfbut.button("disable");
+        wfbut1.button("disable");
+        putXML(where("permittedWorkflowURIs"), xml, function() {
+                refreshWorkflows();
+        });
+}
+
+/** How to update the table of users; called on demand */
+function refreshUsers() {
+	var usertable = $("#userList");
+	getJSON(where("users"), function(data) {
+		$(".userrows").remove();
+		userinfo = [];
+		$.each(data.userList.user, function(idx, url) {
+			usertable.append(userRowHTML(idx));
+			var i = idx;
+			userinfo[i] = {
+				url : url
+			};
+			getJSON(url, function(data) {
+				var model = userinfo[i].model = data.userDesc;
+				$("#username" + i).html(model.username);
+				$("#userlocal" + i).val(model.localUserId).change(function() {
+					updateUser(i, "localUserId", $(this).val());
+				});
+				$("#useron" + i).button().attr("checked", model.enabled)
+						.button("refresh").click(
+								function() {
+									updateUser(i, "enabled", $(this).attr(
+											"checked") == "checked");
+								});
+				$("#useradmin" + i).button().attr("checked", model.admin)
+						.button("refresh").click(
+								function() {
+									updateUser(i, "admin", $(this).attr(
+											"checked") == "checked");
+								});
+				$("#userpass" + i).button({
+					icons : {
+						primary : "ui-icon-alert"
+					}
+				}).click(function() {
+					updatePasswordUser(i);
+				});
+				$("#userdel" + i).button({
+					icons : {
+						primary : "ui-icon-trash"
+					},
+					text : false
+				}).click(function() {
+					deleteUser(i);
+				});
+			});
+			return true;
+		});
+	});
+}
+
+/** How to delete a user by index (with dialog) */
+function deleteUser(idx) {
+	$("#dialog-confirm").dialog({
+		modal : true,
+		autoOpen : false,
+		buttons : {
+			"OK" : function() {
+				$(this).dialog("close");
+				deleteUrl(userinfo[idx].url, function() {
+					refreshUsers();
+				});
+			},
+			"Cancel" : function() {
+				$(this).dialog("close");
+			}
+		}
+	});
+	$("#dialog-confirm").dialog("open");
+}
+
+/** How to update a user's password by index (with dialog) */
+function updatePasswordUser(idx) {
+	$("#change-password").val("");
+	$("#change-password2").val("");
+	$("#dialog-password").dialog({
+		modal : true,
+		autoOpen : false,
+		buttons : {
+			"OK" : function() {
+				$(this).dialog("close");
+				var pass = $("#change-password").val();
+				var pass2 = $("#change-password2").val();
+				$("#change-password").val("");
+				$("#change-password2").val("");
+				if (pass.equals(pass2))
+					updateUser(idx, "password", pass);
+			},
+			"Cancel" : function() {
+				$(this).dialog("close");
+				$("#change-password").val("");
+			}
+		}
+	});
+	$("#dialog-password").dialog("open");
+}
+
+/** How to set a specific field of a user record */
+function updateUser(idx, field, value) {
+	var model = userinfo[idx].model;
+	var xml = Node("userDesc", Node("username", model.username),
+			field == "password" ? Node("password", value) : undefined,
+			field == "localUserId" ? Node("localUserId", value)
+					: model.localUserId == undefined ? undefined : Node(
+							"localUserId", model.localUserId), Node("enabled",
+					field == "enabled" ? value : model.enabled), Node("admin",
+					field == "admin" ? value : model.admin));
+	putXML(userinfo[idx].url, xml, function() {
+		refreshUsers();
+	});
+}
+
+/** How to configure all the buttons and entries */
+function connectButtonsAndEntries() {
+	$.each(buttonlist, function(idx, val) {
+		var widget = $("#" + val);
+		var u = where(val);
+		widget.button();
+		getText(u, function(data) {
+			widget.attr('checked', (data + "") != "false");
+			widget.button("refresh");
+		});
+		widget.change(function() {
+			putText(u, widget.attr("checked") == "checked", function(data) {
+				widget.attr('checked', (data + "") != "false");
+				widget.button("refresh");
+				return true;
+			});
+		});
+	});
+	$.each(entries, function(idx, val) {
+		var widget = $("#" + val);
+		var u = where(val);
+		getText(u, function(data) {
+			widget.val(data);
+		});
+		widget.change(function() {
+			putText(u, widget.val(), function(data) {
+				widget.val(data);
+				return true;
+			});
+		});
+	});
+}
+
+/** What happens when the user tries to make a new user */
+function makeNewUser() {
+	var sysid = $("#newSysID").val();
+	var newuserinfo = {
+		admin : $("#newAdmin").attr("checked") == "checked",
+		enabled : $("#newEnabled").attr("checked") == "checked",
+		username : $("#newUsername").val(),
+		password : $("#newPassword").val()
+	};
+	// Blank out the password immediately!
+	$("#newPassword").val("");
+	if (sysid.length > 0) {
+		newuserinfo.localUserId = sysid;
+	}
+	if (newuserinfo.username == "" || newuserinfo.password == "") {
+		alert("Won't create user; need a username and a password!");
+		return;
+	}
+	var xml = newuserinfo = Node("userDesc", Node("username",
+			newuserinfo.username), Node("password", newuserinfo.password),
+			newuserinfo.localUserId == undefined ? undefined : Node(
+					"localUserId", newuserinfo.localUserId), Node("enabled",
+					newuserinfo.enabled), Node("admin", newuserinfo.admin));
+	postXML(where("users"), xml, function() {
+		refreshUsers();
+	});
+}
+
+/** Handle the extra arguments */
+function loadExtraArgs() {
+	getJSON(where("extraArguments"),
+			function(data) {
+				var rows = data.stringList.string || [];
+				if ((typeof rows) == "string")
+					rows = [ rows ];
+				$(".extraargrow").remove();
+				extraAry = rows;
+				var i;
+				function row() {
+					var buf = "<tr class='extraargrow'>";
+					for ( var i = 1; i < arguments.length; i++)
+						buf += "<td>" + arguments[i] + "</td>";
+					return $(arguments[0]).append(buf + "</tr>");
+				}
+				function delbutn(id, what) {
+					return "<button id='" + id + "' title='Delete this " + what
+							+ ".'>Del</button>";
+				}
+				for (i = 0; i < extraAry.length; i++) {
+					var rowid = "extradel" + i;
+					if (rows[i].match("^-D")) {
+						var m = rows[i].match("^-D([^=]*)=(.*)$");
+						row("#extraArguments-prop", delbutn(rowid,
+								"property assignment"), "<tt><b>-D</b>" + m[1]
+								+ "<b>=</b>" + m[2] + "</tt>");
+					} else if (rows[i].match("-E")) {
+						var m = rows[i].match("^-E([^=]*)=(.*)$");
+						row("#extraArguments-env", delbutn(rowid,
+								"environment assignment"), "<tt><b>-E</b>"
+								+ m[1] + "<b>=</b>" + m[2] + "</tt>");
+					} else {
+						var m = rows[i].match("^-J(.*)$");
+						row("#extraArguments-runtime", delbutn(rowid,
+								"runtime parameter"), "<tt><b>-J</b>" + m[1]
+								+ "</tt>");
+					}
+					$("#" + rowid).button({
+						icons : {
+							primary : "ui-icon-trash"
+						},
+						text : false
+					}).click(
+							(function(row) {
+								return function() {
+									extraAry.splice(row, 1);
+									var xml = NodeAll("stringList", "string",
+											extraAry);
+									putXML(where("extraArguments"), xml,
+											function() {
+												loadExtraArgs();
+											});
+								};
+							})(i));
+				}
+			});
+}
+
+/** Run a dialog for creating an extra argument. */
+function addExtraArg(dialogId, prefix, part1id, part2id) {
+	$(dialogId).dialog({
+		modal : true,
+		autoOpen : false,
+		buttons : {
+			"OK" : function() {
+				$(this).dialog("close");
+				var str = prefix + $(part1id).val();
+				if (part2id != undefined)
+					str += "=" + $(part2id).val();
+				extraAry.push(str);
+				var xml = NodeAll("stringList", "string", extraAry);
+				putXML(where("extraArguments"), xml, function() {
+					loadExtraArgs();
+				});
+			},
+			"Cancel" : function() {
+				$(this).dialog("close");
+			}
+		}
+	});
+	$(dialogId).dialog("open");
+}
+
+/** Start everything going on page load */
+$(function() {
+	// Must be done in this order because the accordion is inside a tab
+	$("#a-worker").accordion({
+		collapsible : true,
+		fillSpace : true,
+		autoHeight : false
+	});
+	$("#body").tabs({
+		selected : 0
+	});
+	$("#saveWorkflows").button({
+		disabled : true
+	}).click(function(event) {
+		saveWorkflows();
+		event.preventDefault();
+	});
+	$("#refreshWorkflows").button({
+		disabled : true
+	}).click(function(event) {
+		refreshWorkflows();
+		event.preventDefault();
+	});
+	$("#emptyWorkflows").button({
+                disabled : true
+        }).click(function(event) {
+                emptyWorkflows();
+                event.preventDefault();
+        });
+
+	// Make the link to the list of usage records point correctly
+	// Original plan called for browsable table, but that's too slow
+	$("#ur").attr("href", where("usageRecords"));
+
+	connectButtonsAndEntries();
+	updateRO();
+	setInterval(updateRO, 30000);
+	refreshUsers();
+	refreshWorkflows();
+	$("#newEnabled").button();
+	$("#newAdmin").button({
+		icons : {
+			primary : "ui-icon-alert"
+		}
+	});
+	$("#makeNewUser").button().click(function() {
+		makeNewUser();
+	});
+	$("#extra-prop-add").button().click(function() {
+		addExtraArg("#dialog-property", "-D", "#prop-key", "#prop-value");
+	});
+	$("#extra-env-add").button().click(function() {
+		addExtraArg("#dialog-environment", "-E", "#env-key", "#env-value");
+	});
+	$("#extra-run-add").button().click(function() {
+		addExtraArg("#dialog-runtime", "-J", "#runtime-value");
+	});
+	loadExtraArgs();
+});


[09/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
new file mode 100644
index 0000000..22158d5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
@@ -0,0 +1,967 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.lang.System.currentTimeMillis;
+import static java.util.Calendar.MINUTE;
+import static java.util.Collections.sort;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.UUID.randomUUID;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
+import static org.taverna.server.master.worker.RunConnection.NAME_LENGTH;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PipedOutputStream;
+import java.rmi.MarshalledObject;
+import java.rmi.RemoteException;
+import java.security.GeneralSecurityException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.localworker.remote.IllegalStateTransitionException;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.taverna.server.localworker.remote.RemoteFile;
+import org.taverna.server.localworker.remote.RemoteInput;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.remote.StillWorkingOnItException;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+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.NoListenerException;
+import org.taverna.server.master.exceptions.OverloadedException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+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.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Bridging shim between the WebApp world and the RMI world.
+ * 
+ * @author Donal Fellows
+ */
+@SuppressWarnings("serial")
+public class RemoteRunDelegate implements TavernaRun {
+	private transient Log log = getLog("Taverna.Server.Worker");
+	transient TavernaSecurityContext secContext;
+	Date creationInstant;
+	Workflow workflow;
+	Date expiry;
+	HashSet<String> readers;
+	HashSet<String> writers;
+	HashSet<String> destroyers;
+	transient String id;
+	transient RemoteSingleRun run;
+	transient RunDBSupport db;
+	transient FactoryBean factory;
+	boolean doneTransitionToFinished;
+	boolean generateProvenance;// FIXME expose
+	String name;
+	private static final String ELLIPSIS = "...";
+
+	public RemoteRunDelegate(Date creationInstant, Workflow workflow,
+			RemoteSingleRun rsr, int defaultLifetime, RunDBSupport db, UUID id,
+			boolean generateProvenance, FactoryBean factory) {
+		if (rsr == null)
+			throw new IllegalArgumentException("remote run must not be null");
+		this.creationInstant = creationInstant;
+		this.workflow = workflow;
+		Calendar c = Calendar.getInstance();
+		c.add(MINUTE, defaultLifetime);
+		this.expiry = c.getTime();
+		this.run = rsr;
+		this.db = db;
+		this.generateProvenance = generateProvenance;
+		this.factory = factory;
+		try {
+			this.name = "";
+			String ci = " " + creationInstant;
+			String n = workflow.getName();
+			if (n.length() > NAME_LENGTH - ci.length())
+				n = n.substring(0,
+						NAME_LENGTH - ci.length() - ELLIPSIS.length())
+						+ ELLIPSIS;
+			this.name = n + ci;
+		} catch (Exception e) {
+			// Ignore; it's just a name, not something important.
+		}
+		if (id != null)
+			this.id = id.toString();
+	}
+
+	RemoteRunDelegate() {
+	}
+
+	/**
+	 * Get the types of listener supported by this run.
+	 * 
+	 * @return A list of listener type names.
+	 * @throws RemoteException
+	 *             If anything goes wrong.
+	 */
+	public List<String> getListenerTypes() throws RemoteException {
+		return run.getListenerTypes();
+	}
+
+	@Override
+	public void addListener(Listener listener) {
+		if (listener instanceof ListenerDelegate)
+			try {
+				run.addListener(((ListenerDelegate) listener).getRemote());
+			} catch (RemoteException e) {
+				log.warn("communication problem adding listener", e);
+			} catch (ImplementationException e) {
+				log.warn("implementation problem adding listener", e);
+			}
+		else
+			log.fatal("bad listener " + listener.getClass()
+					+ "; not applicable remotely!");
+	}
+
+	@Override
+	public String getId() {
+		if (id == null)
+			id = randomUUID().toString();
+		return id;
+	}
+
+	/**
+	 * Attach a listener to a workflow run and return its local delegate.
+	 * 
+	 * @param type
+	 *            The type of listener to create.
+	 * @param config
+	 *            The configuration of the listener.
+	 * @return The local delegate of the listener.
+	 * @throws NoListenerException
+	 *             If anything goes wrong.
+	 */
+	public Listener makeListener(String type, String config)
+			throws NoListenerException {
+		try {
+			return new ListenerDelegate(run.makeListener(type, config));
+		} catch (RemoteException e) {
+			throw new NoListenerException("failed to make listener", e);
+		}
+	}
+
+	@Override
+	public void destroy() {
+		try {
+			run.destroy();
+		} catch (RemoteException | ImplementationException e) {
+			log.warn("failed to destroy run", e);
+		}
+	}
+
+	@Override
+	public Date getExpiry() {
+		return new Date(expiry.getTime());
+	}
+
+	@Override
+	public List<Listener> getListeners() {
+		List<Listener> listeners = new ArrayList<>();
+		try {
+			for (RemoteListener rl : run.getListeners())
+				listeners.add(new ListenerDelegate(rl));
+		} catch (RemoteException e) {
+			log.warn("failed to get listeners", e);
+		}
+		return listeners;
+	}
+
+	@Override
+	public TavernaSecurityContext getSecurityContext() {
+		return secContext;
+	}
+
+	@Override
+	public Status getStatus() {
+		try {
+			switch (run.getStatus()) {
+			case Initialized:
+				return Status.Initialized;
+			case Operating:
+				return Status.Operating;
+			case Stopped:
+				return Status.Stopped;
+			case Finished:
+				return Status.Finished;
+			}
+		} catch (RemoteException e) {
+			log.warn("problem getting remote status", e);
+		}
+		return Status.Finished;
+	}
+
+	@Override
+	public Workflow getWorkflow() {
+		return workflow;
+	}
+
+	@Override
+	public Directory getWorkingDirectory() throws FilesystemAccessException {
+		try {
+			return new DirectoryDelegate(run.getWorkingDirectory());
+		} catch (Throwable e) {
+			if (e.getCause() != null)
+				e = e.getCause();
+			throw new FilesystemAccessException(
+					"problem getting main working directory handle", e);
+		}
+	}
+
+	@Override
+	public void setExpiry(Date d) {
+		if (d.after(new Date()))
+			expiry = new Date(d.getTime());
+		db.flushToDisk(this);
+	}
+
+	@Override
+	public String setStatus(Status s) throws BadStateChangeException {
+		try {
+			log.info("setting status of run " + id + " to " + s);
+			switch (s) {
+			case Initialized:
+				run.setStatus(RemoteStatus.Initialized);
+				break;
+			case Operating:
+				if (run.getStatus() == RemoteStatus.Initialized) {
+					if (!factory.isAllowingRunsToStart())
+						throw new OverloadedException();
+					secContext.conveySecurity();
+				}
+				run.setGenerateProvenance(generateProvenance);
+				run.setStatus(RemoteStatus.Operating);
+				factory.getMasterEventFeed()
+						.started(
+								this,
+								"started run execution",
+								"The execution of run '" + getName()
+										+ "' has started.");
+				break;
+			case Stopped:
+				run.setStatus(RemoteStatus.Stopped);
+				break;
+			case Finished:
+				run.setStatus(RemoteStatus.Finished);
+				break;
+			}
+			return null;
+		} catch (IllegalStateTransitionException e) {
+			throw new BadStateChangeException(e.getMessage());
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e.getMessage(), e.getCause());
+		} catch (GeneralSecurityException | IOException e) {
+			throw new BadStateChangeException(e.getMessage(), e);
+		} catch (ImplementationException e) {
+			if (e.getCause() != null)
+				throw new BadStateChangeException(e.getMessage(), e.getCause());
+			throw new BadStateChangeException(e.getMessage(), e);
+		} catch (StillWorkingOnItException e) {
+			log.info("still working on setting status of run " + id + " to "
+					+ s, e);
+			return e.getMessage();
+		} catch (InterruptedException e) {
+			throw new BadStateChangeException(
+					"interrupted while waiting to insert notification into database");
+		}
+	}
+
+	static void checkBadFilename(String filename)
+			throws FilesystemAccessException {
+		if (filename.startsWith("/"))
+			throw new FilesystemAccessException("filename may not be absolute");
+		if (Arrays.asList(filename.split("/")).contains(".."))
+			throw new FilesystemAccessException(
+					"filename may not refer to parent");
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		try {
+			return run.getInputBaclavaFile();
+		} catch (RemoteException e) {
+			log.warn("problem when fetching input baclava file", e);
+			return null;
+		}
+	}
+
+	@Override
+	public List<Input> getInputs() {
+		ArrayList<Input> inputs = new ArrayList<>();
+		try {
+			for (RemoteInput ri : run.getInputs())
+				inputs.add(new RunInput(ri));
+		} catch (RemoteException e) {
+			log.warn("problem when fetching list of workflow inputs", e);
+		}
+		return inputs;
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		try {
+			return run.getOutputBaclavaFile();
+		} catch (RemoteException e) {
+			log.warn("problem when fetching output baclava file", e);
+			return null;
+		}
+	}
+
+	@Override
+	public Input makeInput(String name) throws BadStateChangeException {
+		try {
+			return new RunInput(run.makeInput(name));
+		} catch (RemoteException e) {
+			throw new BadStateChangeException("failed to make input", e);
+		}
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		checkBadFilename(filename);
+		try {
+			run.setInputBaclavaFile(filename);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException(
+					"cannot set input baclava file name", e);
+		}
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		checkBadFilename(filename);
+		try {
+			run.setOutputBaclavaFile(filename);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException(
+					"cannot set output baclava file name", e);
+		}
+	}
+
+	@Override
+	public Date getCreationTimestamp() {
+		return creationInstant == null ? null : new Date(
+				creationInstant.getTime());
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		try {
+			return run.getFinishTimestamp();
+		} catch (RemoteException e) {
+			log.info("failed to get finish timestamp", e);
+			return null;
+		}
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		try {
+			return run.getStartTimestamp();
+		} catch (RemoteException e) {
+			log.info("failed to get finish timestamp", e);
+			return null;
+		}
+	}
+
+	/**
+	 * @param readers
+	 *            the readers to set
+	 */
+	public void setReaders(Set<String> readers) {
+		this.readers = new HashSet<>(readers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the readers
+	 */
+	public Set<String> getReaders() {
+		return readers == null ? new HashSet<String>()
+				: unmodifiableSet(readers);
+	}
+
+	/**
+	 * @param writers
+	 *            the writers to set
+	 */
+	public void setWriters(Set<String> writers) {
+		this.writers = new HashSet<>(writers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the writers
+	 */
+	public Set<String> getWriters() {
+		return writers == null ? new HashSet<String>()
+				: unmodifiableSet(writers);
+	}
+
+	/**
+	 * @param destroyers
+	 *            the destroyers to set
+	 */
+	public void setDestroyers(Set<String> destroyers) {
+		this.destroyers = new HashSet<>(destroyers);
+		db.flushToDisk(this);
+	}
+
+	/**
+	 * @return the destroyers
+	 */
+	public Set<String> getDestroyers() {
+		return destroyers == null ? new HashSet<String>()
+				: unmodifiableSet(destroyers);
+	}
+
+	private void writeObject(ObjectOutputStream out) throws IOException {
+		out.defaultWriteObject();
+		out.writeUTF(secContext.getOwner().getName());
+		out.writeObject(secContext.getFactory());
+		out.writeObject(new MarshalledObject<>(run));
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		return generateProvenance;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		this.generateProvenance = generateProvenance;
+		db.flushToDisk(this);
+	}
+
+	@SuppressWarnings("unchecked")
+	private void readObject(ObjectInputStream in) throws IOException,
+			ClassNotFoundException {
+		in.defaultReadObject();
+		if (log == null)
+			log = getLog("Taverna.Server.LocalWorker");
+		final String creatorName = in.readUTF();
+		SecurityContextFactory factory = (SecurityContextFactory) in
+				.readObject();
+		try {
+			secContext = factory.create(this,
+					new UsernamePrincipal(creatorName));
+		} catch (RuntimeException | IOException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new SecurityContextReconstructionException(e);
+		}
+		run = ((MarshalledObject<RemoteSingleRun>) in.readObject()).get();
+	}
+
+	public void setSecurityContext(TavernaSecurityContext tavernaSecurityContext) {
+		secContext = tavernaSecurityContext;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void setName(@Nonnull String name) {
+		if (name.length() > RunConnection.NAME_LENGTH)
+			this.name = name.substring(0, RunConnection.NAME_LENGTH);
+		else
+			this.name = name;
+		db.flushToDisk(this);
+	}
+
+	@Override
+	public void ping() throws UnknownRunException {
+		try {
+			run.ping();
+		} catch (RemoteException e) {
+			throw new UnknownRunException(e);
+		}
+	}
+}
+
+abstract class DEDelegate implements DirectoryEntry {
+	Log log = getLog("Taverna.Server.Worker");
+	private RemoteDirectoryEntry entry;
+	private String name;
+	private String full;
+	private Date cacheModTime;
+	private long cacheQueryTime = 0L;
+
+	DEDelegate(RemoteDirectoryEntry entry) {
+		this.entry = entry;
+	}
+
+	@Override
+	public void destroy() throws FilesystemAccessException {
+		try {
+			entry.destroy();
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to delete directory entry", e);
+		}
+	}
+
+	@Override
+	public String getFullName() {
+		if (full != null)
+			return full;
+		String n = getName();
+		RemoteDirectoryEntry re = entry;
+		try {
+			while (true) {
+				RemoteDirectory parent = re.getContainingDirectory();
+				if (parent == null)
+					break;
+				n = parent.getName() + "/" + n;
+				re = parent;
+			}
+		} catch (RemoteException e) {
+			log.warn("failed to generate full name", e);
+		}
+		return (full = n);
+	}
+
+	@Override
+	public String getName() {
+		if (name == null)
+			try {
+				name = entry.getName();
+			} catch (RemoteException e) {
+				log.error("failed to get name", e);
+			}
+		return name;
+	}
+
+	@Override
+	public Date getModificationDate() {
+		if (cacheModTime == null || currentTimeMillis() - cacheQueryTime < 5000)
+			try {
+				cacheModTime = entry.getModificationDate();
+				cacheQueryTime = currentTimeMillis();
+			} catch (RemoteException e) {
+				log.error("failed to get modification time", e);
+			}
+		return cacheModTime;
+	}
+
+	@Override
+	public int compareTo(DirectoryEntry de) {
+		return getFullName().compareTo(de.getFullName());
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		return o != null && o instanceof DEDelegate
+				&& getFullName().equals(((DEDelegate) o).getFullName());
+	}
+
+	@Override
+	public int hashCode() {
+		return getFullName().hashCode();
+	}
+}
+
+class DirectoryDelegate extends DEDelegate implements Directory {
+	RemoteDirectory rd;
+
+	DirectoryDelegate(RemoteDirectory dir) {
+		super(dir);
+		rd = dir;
+	}
+
+	@Override
+	public Collection<DirectoryEntry> getContents()
+			throws FilesystemAccessException {
+		ArrayList<DirectoryEntry> result = new ArrayList<>();
+		try {
+			for (RemoteDirectoryEntry rde : rd.getContents()) {
+				if (rde instanceof RemoteDirectory)
+					result.add(new DirectoryDelegate((RemoteDirectory) rde));
+				else
+					result.add(new FileDelegate((RemoteFile) rde));
+			}
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to get directory contents", e);
+		}
+		return result;
+	}
+
+	@Override
+	public Collection<DirectoryEntry> getContentsByDate()
+			throws FilesystemAccessException {
+		ArrayList<DirectoryEntry> result = new ArrayList<>(getContents());
+		sort(result, new DateComparator());
+		return result;
+	}
+
+	static class DateComparator implements Comparator<DirectoryEntry> {
+		@Override
+		public int compare(DirectoryEntry a, DirectoryEntry b) {
+			return a.getModificationDate().compareTo(b.getModificationDate());
+		}
+	}
+
+	@Override
+	public File makeEmptyFile(Principal actor, String name)
+			throws FilesystemAccessException {
+		try {
+			return new FileDelegate(rd.makeEmptyFile(name));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to make empty file", e);
+		}
+	}
+
+	@Override
+	public Directory makeSubdirectory(Principal actor, String name)
+			throws FilesystemAccessException {
+		try {
+			return new DirectoryDelegate(rd.makeSubdirectory(name));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to make subdirectory",
+					e);
+		}
+	}
+
+	@Override
+	public ZipStream getContentsAsZip() throws FilesystemAccessException {
+		ZipStream zs = new ZipStream();
+
+		final ZipOutputStream zos;
+		try {
+			zos = new ZipOutputStream(new PipedOutputStream(zs));
+		} catch (IOException e) {
+			throw new FilesystemAccessException("problem building zip stream",
+					e);
+		}
+		Thread t = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					zipDirectory(rd, null, zos);
+				} catch (IOException e) {
+					log.warn("problem when zipping directory", e);
+				} finally {
+					closeQuietly(zos);
+				}
+			}
+		});
+		t.setDaemon(true);
+		t.start();
+		return zs;
+	}
+
+	/**
+	 * Compresses a directory tree into a ZIP.
+	 * 
+	 * @param dir
+	 *            The directory to compress.
+	 * @param base
+	 *            The base name of the directory (or <tt>null</tt> if this is
+	 *            the root directory of the ZIP).
+	 * @param zos
+	 *            Where to write the compressed data.
+	 * @throws RemoteException
+	 *             If some kind of problem happens with the remote delegates.
+	 * @throws IOException
+	 *             If we run into problems with reading or writing data.
+	 */
+	void zipDirectory(RemoteDirectory dir, String base, ZipOutputStream zos)
+			throws RemoteException, IOException {
+		for (RemoteDirectoryEntry rde : dir.getContents()) {
+			String name = rde.getName();
+			if (base != null)
+				name = base + "/" + name;
+			if (rde instanceof RemoteDirectory) {
+				RemoteDirectory rd = (RemoteDirectory) rde;
+				zipDirectory(rd, name, zos);
+			} else {
+				RemoteFile rf = (RemoteFile) rde;
+				zos.putNextEntry(new ZipEntry(name));
+				try {
+					int off = 0;
+					while (true) {
+						byte[] c = rf.getContents(off, 64 * 1024);
+						if (c == null || c.length == 0)
+							break;
+						zos.write(c);
+						off += c.length;
+					}
+				} finally {
+					zos.closeEntry();
+				}
+			}
+		}
+	}
+}
+
+class FileDelegate extends DEDelegate implements File {
+	RemoteFile rf;
+
+	FileDelegate(RemoteFile f) {
+		super(f);
+		this.rf = f;
+	}
+
+	@Override
+	public byte[] getContents(int offset, int length)
+			throws FilesystemAccessException {
+		try {
+			return rf.getContents(offset, length);
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to read file contents",
+					e);
+		}
+	}
+
+	@Override
+	public long getSize() throws FilesystemAccessException {
+		try {
+			return rf.getSize();
+		} catch (IOException e) {
+			throw new FilesystemAccessException("failed to get file length", e);
+		}
+	}
+
+	@Override
+	public void setContents(byte[] data) throws FilesystemAccessException {
+		try {
+			rf.setContents(data);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to write file contents", e);
+		}
+	}
+
+	@Override
+	public void appendContents(byte[] data) throws FilesystemAccessException {
+		try {
+			rf.appendContents(data);
+		} catch (IOException e) {
+			throw new FilesystemAccessException(
+					"failed to write file contents", e);
+		}
+	}
+
+	@Override
+	public void copy(File from) throws FilesystemAccessException {
+		FileDelegate fromFile;
+		try {
+			fromFile = (FileDelegate) from;
+		} catch (ClassCastException e) {
+			throw new FilesystemAccessException("different types of File?!");
+		}
+
+		try {
+			rf.copy(fromFile.rf);
+		} catch (Exception e) {
+			throw new FilesystemAccessException("failed to copy file contents",
+					e);
+		}
+		return;
+	}
+}
+
+class ListenerDelegate implements Listener {
+	private Log log = getLog("Taverna.Server.Worker");
+	private RemoteListener r;
+	String conf;
+
+	ListenerDelegate(RemoteListener l) {
+		r = l;
+	}
+
+	RemoteListener getRemote() {
+		return r;
+	}
+
+	@Override
+	public String getConfiguration() {
+		try {
+			if (conf == null)
+				conf = r.getConfiguration();
+		} catch (RemoteException e) {
+			log.warn("failed to get configuration", e);
+		}
+		return conf;
+	}
+
+	@Override
+	public String getName() {
+		try {
+			return r.getName();
+		} catch (RemoteException e) {
+			log.warn("failed to get name", e);
+			return "UNKNOWN NAME";
+		}
+	}
+
+	@Override
+	public String getProperty(String propName) throws NoListenerException {
+		try {
+			return r.getProperty(propName);
+		} catch (RemoteException e) {
+			throw new NoListenerException("no such property: " + propName, e);
+		}
+	}
+
+	@Override
+	public String getType() {
+		try {
+			return r.getType();
+		} catch (RemoteException e) {
+			log.warn("failed to get type", e);
+			return "UNKNOWN TYPE";
+		}
+	}
+
+	@Override
+	public String[] listProperties() {
+		try {
+			return r.listProperties();
+		} catch (RemoteException e) {
+			log.warn("failed to list properties", e);
+			return new String[0];
+		}
+	}
+
+	@Override
+	public void setProperty(String propName, String value)
+			throws NoListenerException, BadPropertyValueException {
+		try {
+			r.setProperty(propName, value);
+		} catch (RemoteException e) {
+			log.warn("failed to set property", e);
+			if (e.getCause() != null
+					&& e.getCause() instanceof RuntimeException)
+				throw new NoListenerException("failed to set property",
+						e.getCause());
+			if (e.getCause() != null && e.getCause() instanceof Exception)
+				throw new BadPropertyValueException("failed to set property",
+						e.getCause());
+			throw new BadPropertyValueException("failed to set property", e);
+		}
+	}
+}
+
+class RunInput implements Input {
+	private final RemoteInput i;
+
+	RunInput(RemoteInput remote) {
+		this.i = remote;
+	}
+
+	@Override
+	public String getFile() {
+		try {
+			return i.getFile();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public String getName() {
+		try {
+			return i.getName();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public String getValue() {
+		try {
+			return i.getValue();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public void setFile(String file) throws FilesystemAccessException,
+			BadStateChangeException {
+		checkBadFilename(file);
+		try {
+			i.setFile(file);
+		} catch (RemoteException e) {
+			throw new FilesystemAccessException("cannot set file for input", e);
+		}
+	}
+
+	@Override
+	public void setValue(String value) throws BadStateChangeException {
+		try {
+			i.setValue(value);
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e);
+		}
+	}
+
+	@Override
+	public String getDelimiter() {
+		try {
+			return i.getDelimiter();
+		} catch (RemoteException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public void setDelimiter(String delimiter) throws BadStateChangeException {
+		try {
+			if (delimiter != null)
+				delimiter = delimiter.substring(0, 1);
+			i.setDelimiter(delimiter);
+		} catch (RemoteException e) {
+			throw new BadStateChangeException(e);
+		}
+	}
+}
+
+@SuppressWarnings("serial")
+class SecurityContextReconstructionException extends RuntimeException {
+	public SecurityContextReconstructionException(Throwable t) {
+		super("failed to rebuild security context", t);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
new file mode 100644
index 0000000..cf55ea0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static org.taverna.server.master.worker.RunConnection.COUNT_QUERY;
+import static org.taverna.server.master.worker.RunConnection.NAMES_QUERY;
+import static org.taverna.server.master.worker.RunConnection.SCHEMA;
+import static org.taverna.server.master.worker.RunConnection.TABLE;
+import static org.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
+import static org.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
+
+import java.io.IOException;
+import java.rmi.MarshalledObject;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Join;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+
+import org.taverna.server.localworker.remote.RemoteSingleRun;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The representation of the connections to the runs that actually participates
+ * in the persistence system.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(table = TABLE, schema = SCHEMA)
+@Queries({
+		@Query(name = "count", language = "SQL", value = COUNT_QUERY, unique = "true", resultClass = Integer.class),
+		@Query(name = "names", language = "SQL", value = NAMES_QUERY, unique = "false", resultClass = String.class),
+		@Query(name = "unterminated", language = "SQL", value = UNTERMINATED_QUERY, unique = "false", resultClass = String.class),
+		@Query(name = "timedout", language = "SQL", value = TIMEOUT_QUERY, unique = "false", resultClass = String.class) })
+public class RunConnection {
+	static final String SCHEMA = "TAVERNA";
+	static final String TABLE = "RUN_CONNECTION";
+	private static final String FULL_NAME = SCHEMA + "." + TABLE;
+	static final String COUNT_QUERY = "SELECT count(*) FROM " + FULL_NAME;
+	static final String NAMES_QUERY = "SELECT ID FROM " + FULL_NAME;
+	static final String TIMEOUT_QUERY = "SELECT ID FROM " + FULL_NAME
+			+ "   WHERE expiry < CURRENT_TIMESTAMP";
+	static final String UNTERMINATED_QUERY = "SELECT ID FROM " + FULL_NAME
+			+ "   WHERE doneTransitionToFinished = 0";
+	static final int NAME_LENGTH = 48; 
+
+	@PrimaryKey
+	@Column(length = 40)
+	private String id;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = NAME_LENGTH)
+	private String name;
+
+	@Persistent(defaultFetchGroup = "true")
+	private Date creationInstant;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Workflow workflow;
+
+	@Persistent(defaultFetchGroup = "true")
+	private Date expiry;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_READERS", column = "ID")
+	private String[] readers;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_WRITERS", column = "ID")
+	private String[] writers;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Join(table = TABLE + "_DESTROYERS", column = "ID")
+	private String[] destroyers;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private MarshalledObject<RemoteSingleRun> run;
+
+	@Persistent(defaultFetchGroup = "true")
+	private int doneTransitionToFinished;
+
+	@Persistent(defaultFetchGroup = "true")
+	private int generateProvenance;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = 128)
+	String owner;
+
+	@Persistent(defaultFetchGroup = "true")
+	@Column(length = 36)
+	private String securityToken;
+
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private SecurityContextFactory securityContextFactory;
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Credential[] credentials;
+	@Persistent(defaultFetchGroup = "true", serialized = "true")
+	@Column(jdbcType = "BLOB", sqlType = "BLOB")
+	private Trust[] trust;
+
+	private static final String[] STRING_ARY = new String[0];
+
+	public String getId() {
+		return id;
+	}
+
+	public boolean isFinished() {
+		return doneTransitionToFinished != 0;
+	}
+
+	public void setFinished(boolean finished) {
+		doneTransitionToFinished = (finished ? 1 : 0);
+	}
+
+	public boolean isProvenanceGenerated() {
+		return generateProvenance != 0;
+	}
+
+	public void setProvenanceGenerated(boolean generate) {
+		generateProvenance = (generate ? 1 : 0);
+	}
+
+	/**
+	 * Manufacture a persistent representation of the given workflow run. Must
+	 * be called within the context of a transaction.
+	 * 
+	 * @param rrd
+	 *            The remote delegate of the workflow run.
+	 * @return The persistent object.
+	 * @throws IOException
+	 *             If serialisation fails.
+	 */
+	@Nonnull
+	public static RunConnection toDBform(@Nonnull RemoteRunDelegate rrd)
+			throws IOException {
+		RunConnection rc = new RunConnection();
+		rc.id = rrd.id;
+		rc.makeChanges(rrd);
+		return rc;
+	}
+
+	private static List<String> list(String[] ary) {
+		if (ary == null)
+			return emptyList();
+		return asList(ary);
+	}
+
+	/**
+	 * Get the remote run delegate for a particular persistent connection. Must
+	 * be called within the context of a transaction.
+	 * 
+	 * @param db
+	 *            The database facade.
+	 * @return The delegate object.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nonnull
+	public RemoteRunDelegate fromDBform(@Nonnull RunDBSupport db)
+			throws Exception {
+		RemoteRunDelegate rrd = new RemoteRunDelegate();
+		rrd.id = getId();
+		rrd.creationInstant = creationInstant;
+		rrd.workflow = workflow;
+		rrd.expiry = expiry;
+		rrd.readers = new HashSet<>(list(readers));
+		rrd.writers = new HashSet<>(list(writers));
+		rrd.destroyers = new HashSet<>(list(destroyers));
+		rrd.run = run.get();
+		rrd.doneTransitionToFinished = isFinished();
+		rrd.generateProvenance = isProvenanceGenerated();
+		rrd.secContext = securityContextFactory.create(rrd,
+				new UsernamePrincipal(owner));
+		((SecurityContextDelegate)rrd.secContext).setCredentialsAndTrust(credentials,trust);
+		rrd.db = db;
+		rrd.factory = db.getFactory();
+		rrd.name = name;
+		return rrd;
+	}
+
+	/**
+	 * Flush changes from a remote run delegate to the database. Must be called
+	 * within the context of a transaction.
+	 * 
+	 * @param rrd
+	 *            The remote run delegate object that has potential changes.
+	 * @throws IOException
+	 *             If anything goes wrong in serialization.
+	 */
+	public void makeChanges(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		// Properties that are set exactly once
+		if (creationInstant == null) {
+			creationInstant = rrd.getCreationTimestamp();
+			workflow = rrd.getWorkflow();
+			run = new MarshalledObject<>(rrd.run);
+			securityContextFactory = rrd.getSecurityContext().getFactory();
+			owner = rrd.getSecurityContext().getOwner().getName();
+			securityToken = ((org.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
+					.issueNewPassword();
+		}
+		// Properties that are set multiple times
+		expiry = rrd.getExpiry();
+		readers = rrd.getReaders().toArray(STRING_ARY);
+		writers = rrd.getWriters().toArray(STRING_ARY);
+		destroyers = rrd.getDestroyers().toArray(STRING_ARY);
+		credentials = rrd.getSecurityContext().getCredentials();
+		trust = rrd.getSecurityContext().getTrusted();
+		if (rrd.name.length() > NAME_LENGTH)
+			this.name = rrd.name.substring(0, NAME_LENGTH);
+		else
+			this.name = rrd.name;
+		setFinished(rrd.doneTransitionToFinished);
+		setProvenanceGenerated(rrd.generateProvenance);
+	}
+
+	public String getSecurityToken() {
+		return securityToken;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
new file mode 100644
index 0000000..2aa7ed1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.taverna.server.master.notification.NotificationEngine;
+
+/**
+ * The interface to the database of runs.
+ * 
+ * @author Donal Fellows
+ */
+public interface RunDBSupport {
+	/**
+	 * Scan each run to see if it has finished yet and issue registered
+	 * notifications if it has.
+	 */
+	void checkForFinishNow();
+
+	/**
+	 * Remove currently-expired runs from this database.
+	 */
+	void cleanNow();
+
+	/**
+	 * How many runs are stored in the database.
+	 * 
+	 * @return The current size of the run table.
+	 */
+	int countRuns();
+
+	/**
+	 * Ensure that a run gets persisted in the database. It is assumed that the
+	 * value is already in there.
+	 * 
+	 * @param run
+	 *            The run to persist.
+	 */
+	void flushToDisk(@Nonnull RemoteRunDelegate run);
+
+	/**
+	 * Select an arbitrary representative run.
+	 * 
+	 * @return The selected run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nullable
+	RemoteRunDelegate pickArbitraryRun() throws Exception;
+
+	/**
+	 * Get a list of all the run names.
+	 * 
+	 * @return The names (i.e., UUIDs) of all the runs.
+	 */
+	@Nonnull
+	List<String> listRunNames();
+
+	/**
+	 * @param notificationEngine
+	 *            A reference to the notification fabric bean.
+	 */
+	void setNotificationEngine(NotificationEngine notificationEngine);
+
+	/**
+	 * @param notifier
+	 *            A reference to the bean that creates messages about workflow
+	 *            run termination.
+	 */
+	void setNotifier(CompletionNotifier notifier);
+
+	/**
+	 * @return A reference to the actual factory for remote runs.
+	 */
+	FactoryBean getFactory();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
new file mode 100644
index 0000000..cedb4b5
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.lang.Integer.parseInt;
+import static java.util.UUID.randomUUID;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.exceptions.UnknownRunException;
+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.notification.NotificationEngine;
+import org.taverna.server.master.notification.NotificationEngine.Message;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * The main facade bean that interfaces to the database of runs.
+ * 
+ * @author Donal Fellows
+ */
+public class RunDatabase implements RunStore, RunDBSupport {
+	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
+	RunDatabaseDAO dao;
+	CompletionNotifier backupNotifier;
+	Map<String, CompletionNotifier> typedNotifiers;
+	private NotificationEngine notificationEngine;
+	@Autowired
+	private FactoryBean factory;
+	private Map<String, TavernaRun> cache = new HashMap<>();
+
+	@Override
+	@Required
+	public void setNotifier(CompletionNotifier n) {
+		backupNotifier = n;
+	}
+
+	public void setTypeNotifiers(List<CompletionNotifier> notifiers) {
+		typedNotifiers = new HashMap<>();
+		for (CompletionNotifier n : notifiers)
+			typedNotifiers.put(n.getName(), n);
+	}
+
+	@Required
+	@Override
+	public void setNotificationEngine(NotificationEngine notificationEngine) {
+		this.notificationEngine = notificationEngine;
+	}
+
+	@Required
+	public void setDao(RunDatabaseDAO dao) {
+		this.dao = dao;
+	}
+
+	@Override
+	public void checkForFinishNow() {
+		/*
+		 * Get which runs are actually newly finished; this requires getting the
+		 * candidates from the database and *then* doing the expensive requests
+		 * to the back end to find out the status.
+		 */
+		Map<String, RemoteRunDelegate> notifiable = new HashMap<>();
+		for (RemoteRunDelegate p : dao.getPotentiallyNotifiable())
+			if (p.getStatus() == Status.Finished)
+				notifiable.put(p.getId(), p);
+
+		// Check if there's nothing more to do
+		if (notifiable.isEmpty())
+			return;
+
+		/*
+		 * Tell the database about the ones we've got.
+		 */
+		dao.markFinished(notifiable.keySet());
+
+		/*
+		 * Send out the notifications. The notification addresses are stored in
+		 * the back-end engine, so this is *another* thing that can take time.
+		 */
+		for (RemoteRunDelegate rrd : notifiable.values())
+			for (Listener l : rrd.getListeners())
+				if (l.getName().equals("io")) {
+					try {
+						notifyFinished(rrd.id, l, rrd);
+					} catch (Exception e) {
+						log.warn("failed to do notification of completion", e);
+					}
+					break;
+				}
+	}
+
+	@Override
+	public void cleanNow() {
+		List<String> cleaned;
+		try {
+			cleaned = dao.doClean();
+		} catch (Exception e) {
+			log.warn("failure during deletion of expired runs", e);
+			return;
+		}
+		synchronized (cache) {
+			for (String id : cleaned)
+				cache.remove(id);
+		}
+	}
+
+	@Override
+	public int countRuns() {
+		return dao.countRuns();
+	}
+
+	@Override
+	public void flushToDisk(RemoteRunDelegate run) {
+		try {
+			dao.flushToDisk(run);
+		} catch (IOException e) {
+			throw new RuntimeException(
+					"unexpected problem when persisting run record in database",
+					e);
+		}
+	}
+
+	@Override
+	public RemoteRunDelegate pickArbitraryRun() throws Exception {
+		return dao.pickArbitraryRun();
+	}
+
+	@Override
+	public List<String> listRunNames() {
+		return dao.listRunNames();
+	}
+
+	@Nullable
+	private TavernaRun get(String uuid) {
+		TavernaRun run = null;
+		synchronized (cache) {
+			run = cache.get(uuid);
+		}
+		try {
+			if (run != null)
+				run.ping();
+		} catch (UnknownRunException e) {
+			if (log.isDebugEnabled())
+				log.debug("stale mapping in cache?", e);
+			// Don't need to flush the cache; this happens when cleaning anyway
+			run = null;
+		}
+		if (run == null)
+			run = dao.get(uuid);
+		return run;
+	}
+
+	@Override
+	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException {
+		// Check first to see if the 'uuid' actually looks like a UUID; if
+		// not, throw it out immediately without logging an exception.
+		try {
+			UUID.fromString(uuid);
+		} catch (IllegalArgumentException e) {
+			if (log.isDebugEnabled())
+				log.debug("run ID does not look like UUID; rejecting...");
+			throw new UnknownRunException();
+		}
+		TavernaRun run = get(uuid);
+		if (run != null && (user == null || p.permitAccess(user, run)))
+			return run;
+		throw new UnknownRunException();
+	}
+
+	@Override
+	public TavernaRun getRun(String uuid) throws UnknownRunException {
+		TavernaRun run = get(uuid);
+		if (run != null)
+			return run;
+		throw new UnknownRunException();
+	}
+
+	@Override
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		synchronized (cache) {
+			Map<String, TavernaRun> cached = new HashMap<>();
+			for (Entry<String, TavernaRun> e : cache.entrySet()) {
+				TavernaRun r = e.getValue();
+				if (p.permitAccess(user, r))
+					cached.put(e.getKey(), r);
+			}
+			if (!cached.isEmpty())
+				return cached;
+		}
+		return dao.listRuns(user, p);
+	}
+
+	private void logLength(String message, Object obj) {
+		if (!log.isDebugEnabled())
+			return;
+		try {
+			ByteArrayOutputStream baos = new ByteArrayOutputStream();
+			try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+				oos.writeObject(obj);
+			}
+			log.debug(message + ": " + baos.size());
+		} catch (Exception e) {
+			log.warn("oops", e);
+		}
+	}
+
+	@Override
+	public String registerRun(TavernaRun run) {
+		if (!(run instanceof RemoteRunDelegate))
+			throw new IllegalArgumentException(
+					"run must be created by localworker package");
+		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
+		if (rrd.id == null)
+			rrd.id = randomUUID().toString();
+		logLength("RemoteRunDelegate serialized length", rrd);
+		try {
+			dao.persistRun(rrd);
+		} catch (IOException e) {
+			throw new RuntimeException(
+					"unexpected problem when persisting run record in database",
+					e);
+		}
+		synchronized (cache) {
+			cache.put(rrd.getId(), run);
+		}
+		return rrd.getId();
+	}
+
+	@Override
+	public void unregisterRun(String uuid) {
+		try {
+			if (dao.unpersistRun(uuid))
+				synchronized (cache) {
+					cache.remove(uuid);
+				}
+		} catch (RuntimeException e) {
+			if (log.isDebugEnabled())
+				log.debug("problem persisting the deletion of the run " + uuid,
+						e);
+		}
+	}
+
+	/**
+	 * Process the event that a run has finished.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param io
+	 *            The io listener of the run (used to get information about the
+	 *            run).
+	 * @param run
+	 *            The handle to the run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	private void notifyFinished(final String name, Listener io,
+			final RemoteRunDelegate run) throws Exception {
+		String to = io.getProperty("notificationAddress");
+		final int code;
+		try {
+			code = parseInt(io.getProperty("exitcode"));
+		} catch (NumberFormatException nfe) {
+			// Ignore; not much we can do here...
+			return;
+		}
+
+		notificationEngine.dispatchMessage(run, to, new Message() {
+			private CompletionNotifier getNotifier(String type) {
+				CompletionNotifier n = typedNotifiers.get(type);
+				if (n == null)
+					n = backupNotifier;
+				return n;
+			}
+
+			@Override
+			public String getContent(String type) {
+				return getNotifier(type).makeCompletionMessage(name, run, code);
+			}
+
+			@Override
+			public String getTitle(String type) {
+				return getNotifier(type).makeMessageSubject(name, run, code);
+			}
+		});
+	}
+
+	@Override
+	public FactoryBean getFactory() {
+		return factory;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
new file mode 100644
index 0000000..51931c0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static org.taverna.server.master.worker.RunConnection.toDBform;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jdo.annotations.PersistenceAware;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.JDOSupport;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * This handles storing runs, interfacing with the underlying state engine as
+ * necessary.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceAware
+public class RunDatabaseDAO extends JDOSupport<RunConnection> {
+	public RunDatabaseDAO() {
+		super(RunConnection.class);
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
+	private RunDatabase facade;
+
+	@Required
+	public void setFacade(RunDatabase facade) {
+		this.facade = facade;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+	@SuppressWarnings("unchecked")
+	private List<String> nameRuns() {
+		if (log.isDebugEnabled())
+			log.debug("fetching all run names");
+		return (List<String>) namedQuery("names").execute();
+	}
+
+	/**
+	 * @return The number of workflow runs in the database.
+	 */
+	@WithinSingleTransaction
+	public int countRuns() {
+		if (log.isDebugEnabled())
+			log.debug("counting the number of runs");
+		return (Integer) namedQuery("count").execute();
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> expiredRuns() {
+		return (List<String>) namedQuery("timedout").execute();
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<String> unterminatedRuns() {
+		return (List<String>) namedQuery("unterminated").execute();
+	}
+
+	@Nullable
+	private RunConnection pickRun(@Nonnull String name) {
+		if (log.isDebugEnabled())
+			log.debug("fetching the run called " + name);
+		try {
+			RunConnection rc = getById(name);
+			if (rc == null)
+				log.warn("no result for " + name);
+			return rc;
+		} catch (RuntimeException e) {
+			log.warn("problem in fetch", e);
+			throw e;
+		}
+	}
+
+	@Nullable
+	@WithinSingleTransaction
+	public String getSecurityToken(@Nonnull String name) {
+		RunConnection rc = getById(name);
+		if (rc == null)
+			return null;
+		return rc.getSecurityToken();
+	}
+
+	private void persist(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		persist(toDBform(rrd));
+	}
+
+	@Nonnull
+	private List<RunConnection> allRuns() {
+		try {
+			List<RunConnection> rcs = new ArrayList<>();
+			List<String> names = nameRuns();
+			for (String id : names) {
+				try {
+					if (id != null)
+						rcs.add(pickRun(id));
+				} catch (RuntimeException e) {
+					continue;
+				}
+			}
+			return rcs;
+		} catch (RuntimeException e) {
+			log.warn("problem in fetch", e);
+			throw e;
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+	/**
+	 * Obtain a workflow run handle.
+	 * 
+	 * @param name
+	 *            The identifier of the run.
+	 * @return The run handle, or <tt>null</tt> if there is no such run.
+	 */
+	@Nullable
+	@WithinSingleTransaction
+	public TavernaRun get(String name) {
+		try {
+			RunConnection rc = pickRun(name);
+			return (rc == null) ? null : rc.fromDBform(facade);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Get the runs that a user can read things from.
+	 * 
+	 * @param user
+	 *            Who is asking?
+	 * @param p
+	 *            The policy that determines what they can see.
+	 * @return A mapping from run IDs to run handles.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		Map<String, TavernaRun> result = new HashMap<>();
+		for (String id : nameRuns())
+			try {
+				RemoteRunDelegate rrd = pickRun(id).fromDBform(facade);
+				if (p.permitAccess(user, rrd))
+					result.put(id, rrd);
+			} catch (Exception e) {
+				continue;
+			}
+		return result;
+	}
+
+	/**
+	 * @return A list of the IDs for all workflow runs.
+	 */
+	@Nonnull
+	@WithinSingleTransaction
+	public List<String> listRunNames() {
+		List<String> runNames = new ArrayList<>();
+		for (RunConnection rc : allRuns())
+			if (rc.getId() != null)
+				runNames.add(rc.getId());
+		return runNames;
+	}
+
+	/**
+	 * @return An arbitrary, representative workflow run.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Nullable
+	@WithinSingleTransaction
+	public RemoteRunDelegate pickArbitraryRun() throws Exception {
+		for (RunConnection rc : allRuns()) {
+			if (rc.getId() == null)
+				continue;
+			return rc.fromDBform(facade);
+		}
+		return null;
+	}
+
+	/**
+	 * Make a workflow run persistent. Must only be called once per workflow
+	 * run.
+	 * 
+	 * @param rrd
+	 *            The workflow run to persist.
+	 * @throws IOException
+	 *             If anything goes wrong with serialisation of the run.
+	 */
+	@WithinSingleTransaction
+	public void persistRun(@Nonnull RemoteRunDelegate rrd) throws IOException {
+		persist(rrd);
+	}
+
+	/**
+	 * Stop a workflow run from being persistent.
+	 * 
+	 * @param name
+	 *            The ID of the run.
+	 * @return Whether a deletion happened.
+	 */
+	@WithinSingleTransaction
+	public boolean unpersistRun(String name) {
+		RunConnection rc = pickRun(name);
+		if (rc != null)
+			delete(rc);
+		return rc != null;
+	}
+
+	/**
+	 * Ensure that the given workflow run is synchronized with the database.
+	 * 
+	 * @param run
+	 *            The run to synchronise.
+	 * @throws IOException
+	 *             If serialization of anything fails.
+	 */
+	@WithinSingleTransaction
+	public void flushToDisk(@Nonnull RemoteRunDelegate run) throws IOException {
+		getById(run.id).makeChanges(run);
+	}
+
+	/**
+	 * Remove all workflow runs that have expired.
+	 * 
+	 * @return The ids of the deleted runs.
+	 */
+	@Nonnull
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<String> doClean() {
+		if (log.isDebugEnabled())
+			log.debug("deleting runs that timed out before " + new Date());
+		List<String> toDelete = expiredRuns();
+		if (log.isDebugEnabled())
+			log.debug("found " + toDelete.size() + " runs to delete");
+		for (String id : toDelete) {
+			RunConnection rc = getById(id);
+			try {
+				rc.fromDBform(facade).run.destroy();
+			} catch (Exception e) {
+				if (log.isDebugEnabled())
+					log.debug("failed to delete execution resource for " + id,
+							e);
+			}
+			delete(rc);
+		}
+		return toDelete;
+	}
+
+	/**
+	 * @return A list of workflow runs that are candidates for doing
+	 *         notification of termination.
+	 */
+	@Nonnull
+	@PerfLogged
+	@WithinSingleTransaction
+	public List<RemoteRunDelegate> getPotentiallyNotifiable() {
+		List<RemoteRunDelegate> toNotify = new ArrayList<>();
+		for (String id : unterminatedRuns())
+			try {
+				RunConnection rc = getById(id);
+				toNotify.add(rc.fromDBform(facade));
+			} catch (Exception e) {
+				log.warn("failed to fetch connection token"
+						+ "for notification of completion check", e);
+			}
+		return toNotify;
+	}
+
+	@PerfLogged
+	@WithinSingleTransaction
+	public void markFinished(@Nonnull Set<String> terminated) {
+		for (String id : terminated) {
+			RunConnection rc = getById(id);
+			if (rc == null)
+				continue;
+			try {
+				rc.fromDBform(facade).doneTransitionToFinished = true;
+				rc.setFinished(true);
+			} catch (Exception e) {
+				log.warn("failed to note termination", e);
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
new file mode 100644
index 0000000..29ac884
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
@@ -0,0 +1,395 @@
+package org.taverna.server.master.worker;
+
+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 java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedMetric;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.master.factories.ConfigurableRunFactory;
+import org.taverna.server.master.localworker.LocalWorkerState;
+
+@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs.")
+public abstract class RunFactoryConfiguration implements ConfigurableRunFactory {
+	protected Log log = LogFactory.getLog("Taverna.Server.Worker");
+	protected LocalWorkerState state;
+	protected RunDBSupport runDB;
+	private int totalRuns = 0;
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	@Autowired(required = true)
+	@Order(0)
+	void setState(LocalWorkerState state) {
+		this.state = state;
+	}
+
+	@Autowired(required = true)
+	@Order(0)
+	void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	/**
+	 * Drop any current references to the registry of runs, and kill off that
+	 * process.
+	 */
+	protected abstract void reinitRegistry();
+
+	/**
+	 * Drop any current references to the run factory subprocess and kill it
+	 * off.
+	 */
+	protected abstract void reinitFactory();
+
+	/** Count the number of operating runs. */
+	protected abstract int operatingCount() throws Exception;
+
+	protected final synchronized void incrementRunCount() {
+		totalRuns++;
+	}
+
+	@Override
+	@ManagedAttribute(description = "Whether it is allowed to start a run executing.", currencyTimeLimit = 30)
+	public final boolean isAllowingRunsToStart() {
+		try {
+			return state.getOperatingLimit() > getOperatingCount();
+		} catch (Exception e) {
+			log.info("failed to get operating run count", e);
+			return false;
+		}
+	}
+
+	@Override
+	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
+	public final String getRegistryHost() {
+		return state.getRegistryHost();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
+	public final void setRegistryHost(String host) {
+		state.setRegistryHost(host);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
+	public final int getRegistryPort() {
+		return state.getRegistryPort();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
+	public final void setRegistryPort(int port) {
+		state.setRegistryPort(port);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
+	public final String getRmiRegistryJar() {
+		return state.getRegistryJar();
+	}
+
+	@Override
+	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
+	public final void setRmiRegistryJar(String rmiRegistryJar) {
+		state.setRegistryJar(rmiRegistryJar);
+		reinitRegistry();
+		reinitFactory();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
+	public final int getMaxRuns() {
+		return state.getMaxRuns();
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
+	public final void setMaxRuns(int maxRuns) {
+		state.setMaxRuns(maxRuns);
+	}
+
+	/** @return How many minutes should a workflow live by default? */
+	@Override
+	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
+	public final int getDefaultLifetime() {
+		return state.getDefaultLifetime();
+	}
+
+	/**
+	 * Set how long a workflow should live by default.
+	 * 
+	 * @param defaultLifetime
+	 *            Default lifetime, in minutes.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
+	public final void setDefaultLifetime(int defaultLifetime) {
+		state.setDefaultLifetime(defaultLifetime);
+	}
+
+	/**
+	 * @return How many milliseconds to wait between checks to see if a worker
+	 *         process has registered.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
+	public final int getSleepTime() {
+		return state.getSleepMS();
+	}
+
+	/**
+	 * @param sleepTime
+	 *            How many milliseconds to wait between checks to see if a
+	 *            worker process has registered.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
+	public final void setSleepTime(int sleepTime) {
+		state.setSleepMS(sleepTime);
+	}
+
+	/**
+	 * @return How many seconds to wait for a worker process to register itself.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
+	public final int getWaitSeconds() {
+		return state.getWaitSeconds();
+	}
+
+	/**
+	 * @param seconds
+	 *            How many seconds to wait for a worker process to register
+	 *            itself.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
+	public final void setWaitSeconds(int seconds) {
+		state.setWaitSeconds(seconds);
+	}
+
+	/** @return The script to run to start running a workflow. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
+	public final String getExecuteWorkflowScript() {
+		return state.getExecuteWorkflowScript();
+	}
+
+	/**
+	 * @param executeWorkflowScript
+	 *            The script to run to start running a workflow.
+	 */
+	@Override
+	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
+	public final void setExecuteWorkflowScript(String executeWorkflowScript) {
+		state.setExecuteWorkflowScript(executeWorkflowScript);
+		reinitFactory();
+	}
+
+	/** @return The location of the JAR implementing the server worker processes. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
+	public final String getServerWorkerJar() {
+		return state.getServerWorkerJar();
+	}
+
+	/**
+	 * @param serverWorkerJar
+	 *            The location of the JAR implementing the server worker
+	 *            processes.
+	 */
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
+	public final void setServerWorkerJar(String serverWorkerJar) {
+		state.setServerWorkerJar(serverWorkerJar);
+		reinitFactory();
+	}
+
+	/** @return The list of additional arguments used to make a worker process. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
+	public final String[] getExtraArguments() {
+		return state.getExtraArgs();
+	}
+
+	/**
+	 * @param extraArguments
+	 *            The list of additional arguments used to make a worker
+	 *            process.
+	 */
+	@Override
+	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
+	public final void setExtraArguments(@Nonnull String[] extraArguments) {
+		state.setExtraArgs(extraArguments);
+		reinitFactory();
+	}
+
+	/** @return Which java executable to run. */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
+	public final String getJavaBinary() {
+		return state.getJavaBinary();
+	}
+
+	/**
+	 * @param javaBinary
+	 *            Which java executable to run.
+	 */
+	@Override
+	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
+	public final void setJavaBinary(@Nonnull String javaBinary) {
+		state.setJavaBinary(javaBinary);
+		reinitFactory();
+	}
+
+	/**
+	 * @return A file containing a password to use when running a program as
+	 *         another user (e.g., with sudo).
+	 */
+	@Nullable
+	@Override
+	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
+	public final String getPasswordFile() {
+		return state.getPasswordFile();
+	}
+
+	/**
+	 * @param passwordFile
+	 *            A file containing a password to use when running a program as
+	 *            another user (e.g., with sudo).
+	 */
+	@Override
+	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
+	public final void setPasswordFile(@Nullable String passwordFile) {
+		state.setPasswordFile(passwordFile);
+		reinitFactory();
+	}
+
+	/**
+	 * @return The location of the JAR implementing the secure-fork process.
+	 */
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
+	public final String getServerForkerJar() {
+		return state.getServerForkerJar();
+	}
+
+	/**
+	 * @param serverForkerJar
+	 *            The location of the JAR implementing the secure-fork process.
+	 */
+	@Override
+	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
+	public final void setServerForkerJar(String forkerJarFilename) {
+		state.setServerForkerJar(forkerJarFilename);
+		reinitFactory();
+	}
+
+	/**
+	 * @return How many times has a workflow run been spawned by this engine.
+	 *         Restarts reset this counter.
+	 */
+	@Override
+	@ManagedMetric(description = "How many times has a workflow run been spawned by this engine.", currencyTimeLimit = 10, metricType = COUNTER, category = "throughput")
+	public final synchronized int getTotalRuns() {
+		return totalRuns;
+	}
+
+	/**
+	 * @return How many checks were done for the worker process the last time a
+	 *         spawn was tried.
+	 */
+	@Override
+	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
+	public abstract int getLastStartupCheckCount();
+
+	@Nonnull
+	@Override
+	@ManagedAttribute(description = "The names of the current runs.", currencyTimeLimit = 5)
+	public final String[] getCurrentRunNames() {
+		List<String> names = runDB.listRunNames();
+		return names.toArray(new String[names.size()]);
+	}
+
+	@Override
+	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
+	public abstract String getFactoryProcessName();
+
+	/**
+	 * @return What was the exit code from the last time the factory subprocess
+	 *         was killed?
+	 */
+	@Override
+	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
+	public abstract Integer getLastExitCode();
+
+	/**
+	 * @return The mapping of user names to RMI factory IDs.
+	 */
+	@Override
+	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
+	public abstract String[] getFactoryProcessMapping();
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
+	public final void setOperatingLimit(int operatingLimit) {
+		state.setOperatingLimit(operatingLimit);
+	}
+
+	@Override
+	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
+	public final int getOperatingLimit() {
+		return state.getOperatingLimit();
+	}
+
+	/**
+	 * @return A count of the number of runs believed to actually be in the
+	 *         {@linkplain uk.org.taverna.server.master.common.Status#Operating
+	 *         operating} state.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	@Override
+	@ManagedMetric(description = "How many workflow runs are currently actually executing.", currencyTimeLimit = 10, metricType = GAUGE, category = "throughput")
+	public final int getOperatingCount() throws Exception {
+		return operatingCount();
+	}
+
+	@Override
+	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
+	public final void setGenerateProvenance(boolean genProv) {
+		state.setGenerateProvenance(genProv);
+	}
+
+	@Override
+	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
+	public final boolean getGenerateProvenance() {
+		return state.getGenerateProvenance();
+	}
+}


[21/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java b/taverna-server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
new file mode 100644
index 0000000..d12d3d8
--- /dev/null
+++ b/taverna-server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.ogf.usage;
+
+import static java.util.UUID.randomUUID;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.transform.dom.DOMSource;
+
+import org.ogf.usage.v1_0.Charge;
+import org.ogf.usage.v1_0.ConsumableResourceType;
+import org.ogf.usage.v1_0.CpuDuration;
+import org.ogf.usage.v1_0.Disk;
+import org.ogf.usage.v1_0.EndTime;
+import org.ogf.usage.v1_0.Host;
+import org.ogf.usage.v1_0.JobName;
+import org.ogf.usage.v1_0.MachineName;
+import org.ogf.usage.v1_0.Memory;
+import org.ogf.usage.v1_0.Network;
+import org.ogf.usage.v1_0.NodeCount;
+import org.ogf.usage.v1_0.Processors;
+import org.ogf.usage.v1_0.ProjectName;
+import org.ogf.usage.v1_0.Queue;
+import org.ogf.usage.v1_0.RecordIdentity;
+import org.ogf.usage.v1_0.ResourceType;
+import org.ogf.usage.v1_0.ServiceLevel;
+import org.ogf.usage.v1_0.StartTime;
+import org.ogf.usage.v1_0.Status;
+import org.ogf.usage.v1_0.SubmitHost;
+import org.ogf.usage.v1_0.Swap;
+import org.ogf.usage.v1_0.TimeDuration;
+import org.ogf.usage.v1_0.TimeInstant;
+import org.ogf.usage.v1_0.UserIdentity;
+import org.ogf.usage.v1_0.WallDuration;
+import org.w3c.dom.Element;
+
+@XmlRootElement(name = "UsageRecord", namespace = "http://schema.ogf.org/urf/2003/09/urf")
+public class JobUsageRecord extends org.ogf.usage.v1_0.UsageRecordType {
+	/**
+	 * Create a new usage record with a random UUID as its identity.
+	 * 
+	 * @throws DatatypeConfigurationException
+	 *             If the factory for XML-relevant datatypes fails to build; not
+	 *             expected.
+	 */
+	public JobUsageRecord() throws DatatypeConfigurationException {
+		datatypeFactory = DatatypeFactory.newInstance();
+		RecordIdentity recid = new RecordIdentity();
+		recid.setRecordId(randomUUID().toString());
+		recid.setCreateTime(datatypeFactory
+				.newXMLGregorianCalendar(new GregorianCalendar()));
+		setRecordIdentity(recid);
+	}
+
+	/**
+	 * Create a new usage record with a random UUID as its identity.
+	 * 
+	 * @param name
+	 *            The name of the job to which this record pertains.
+	 * @throws DatatypeConfigurationException
+	 *             If the factory for XML-relevant datatypes fails to build; not
+	 *             expected.
+	 */
+	public JobUsageRecord(String name) throws DatatypeConfigurationException {
+		this();
+		setJobName(name);
+	}
+
+	@XmlTransient
+	private DatatypeFactory datatypeFactory;
+
+	public Status setStatus(String status) {
+		Status s = new Status();
+		s.setValue(status);
+		setStatus(s);
+		return s;
+	}
+
+	public WallDuration addWallDuration(long millis) {
+		WallDuration wall = new WallDuration();
+		wall.setValue(datatypeFactory.newDuration(millis));
+		getWallDurationOrCpuDurationOrNodeCount().add(wall);
+		return wall;
+	}
+
+	public CpuDuration addCpuDuration(long millis) {
+		CpuDuration cpu = new CpuDuration();
+		cpu.setValue(datatypeFactory.newDuration(millis));
+		getWallDurationOrCpuDurationOrNodeCount().add(cpu);
+		return cpu;
+	}
+
+	public NodeCount addNodeCount(int nodes) {
+		NodeCount nc = new NodeCount();
+		nc.setValue(BigInteger.valueOf(nodes));
+		getWallDurationOrCpuDurationOrNodeCount().add(nc);
+		return nc;
+	}
+
+	public Processors addProcessors(int processors) {
+		Processors pc = new Processors();
+		pc.setValue(BigInteger.valueOf(processors));
+		getWallDurationOrCpuDurationOrNodeCount().add(pc);
+		return pc;
+	}
+
+	public SubmitHost addSubmitHost(String host) {
+		SubmitHost sh = new SubmitHost();
+		sh.setValue(host);
+		getWallDurationOrCpuDurationOrNodeCount().add(sh);
+		return sh;
+	}
+
+	public Host addHost(String host) {
+		Host h = new Host();
+		h.setValue(host);
+		getWallDurationOrCpuDurationOrNodeCount().add(h);
+		return h;
+	}
+
+	public MachineName addMachine(String host) {
+		MachineName machine = new MachineName();
+		machine.setValue(host);
+		getWallDurationOrCpuDurationOrNodeCount().add(machine);
+		return machine;
+	}
+
+	public ProjectName addProject(String project) {
+		ProjectName p = new ProjectName();
+		p.setValue(project);
+		getWallDurationOrCpuDurationOrNodeCount().add(p);
+		return p;
+	}
+
+	public void addStartAndEnd(Date start, Date end) {
+		GregorianCalendar gc;
+
+		gc = new GregorianCalendar();
+		gc.setTime(start);
+		StartTime st = new StartTime();
+		st.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
+		getWallDurationOrCpuDurationOrNodeCount().add(st);
+
+		gc = new GregorianCalendar();
+		gc.setTime(end);
+		EndTime et = new EndTime();
+		et.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
+		getWallDurationOrCpuDurationOrNodeCount().add(et);
+	}
+
+	public Queue addQueue(String queue) {
+		Queue q = new Queue();
+		q.setValue(queue);
+		getWallDurationOrCpuDurationOrNodeCount().add(q);
+		return q;
+	}
+
+	public void addResource(ConsumableResourceType consumable) {
+		getWallDurationOrCpuDurationOrNodeCount().add(consumable);
+	}
+
+	public ResourceType addResource(ResourceType resource) {
+		getWallDurationOrCpuDurationOrNodeCount().add(resource);
+		return resource;
+	}
+
+	public ResourceType addResource(String description, String value) {
+		ResourceType resource = new ResourceType();
+		resource.setDescription(description);
+		resource.setValue(value);
+		getWallDurationOrCpuDurationOrNodeCount().add(resource);
+		return resource;
+	}
+
+	public ServiceLevel addServiceLevel(String service) {
+		ServiceLevel sl = new ServiceLevel();
+		sl.setValue(service);
+		getDiskOrMemoryOrSwap().add(sl);
+		return sl;
+	}
+
+	public Memory addMemory(long memory) {
+		Memory mem = new Memory();
+		mem.setValue(BigInteger.valueOf(memory));
+		getDiskOrMemoryOrSwap().add(mem);
+		return mem;
+	}
+
+	public TimeInstant addTimestamp(Date timestamp, String type) {
+		TimeInstant instant = new TimeInstant();
+		GregorianCalendar gc = new GregorianCalendar();
+		gc.setTime(timestamp);
+		instant.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
+		instant.setType(type);
+		getDiskOrMemoryOrSwap().add(instant);
+		return instant;
+	}
+
+	public TimeDuration addDuration(long millis, String type) {
+		TimeDuration duration = new TimeDuration();
+		duration.setValue(datatypeFactory.newDuration(millis));
+		duration.setType(type);
+		getDiskOrMemoryOrSwap().add(duration);
+		return duration;
+	}
+
+	public Network addNetwork(long value) {
+		Network net = new Network();
+		net.setValue(BigInteger.valueOf(value));
+		getDiskOrMemoryOrSwap().add(net);
+		return net;
+	}
+
+	public Disk addDisk(long value) {
+		Disk disk = new Disk();
+		disk.setValue(BigInteger.valueOf(value));
+		getDiskOrMemoryOrSwap().add(disk);
+		return disk;
+	}
+
+	public Swap addSwap(long value) {
+		Swap net = new Swap();
+		net.setValue(BigInteger.valueOf(value));
+		getDiskOrMemoryOrSwap().add(net);
+		return net;
+	}
+
+	public UserIdentity addUser(String localUID, String globalName) {
+		UserIdentity user = new UserIdentity();
+		user.setLocalUserId(localUID);
+		user.setGlobalUserName(globalName);
+		getUserIdentity().add(user);
+		return user;
+	}
+
+	public JobName setJobName(String name) {
+		JobName jn = new JobName();
+		jn.setValue(name);
+		this.setJobName(jn);
+		return jn;
+	}
+
+	public Charge addCharge(float value) {
+		Charge c = new Charge();
+		c.setValue(value);
+		this.setCharge(c);
+		return c;
+	}
+
+	@SuppressWarnings("unchecked")
+	public <T> T getOfType(Class<T> clazz) {
+		for (Object o : getWallDurationOrCpuDurationOrNodeCount())
+			if (clazz.isInstance(o))
+				return (T) o;
+		for (Object o : getDiskOrMemoryOrSwap())
+			if (clazz.isInstance(o))
+				return (T) o;
+		return null;
+	}
+
+	public String marshal() throws JAXBException {
+		StringWriter writer = new StringWriter();
+		JAXBContext.newInstance(getClass()).createMarshaller()
+				.marshal(this, writer);
+		return writer.toString();
+	}
+
+	private static JAXBContext context;
+	static {
+		try {
+			context = JAXBContext.newInstance(JobUsageRecord.class);
+		} catch (JAXBException e) {
+			throw new RuntimeException("failed to handle JAXB annotated class",
+					e);
+		}
+	}
+
+	public static JobUsageRecord unmarshal(String s) throws JAXBException {
+		return (JobUsageRecord) context.createUnmarshaller().unmarshal(
+				new StringReader(s));
+	}
+
+	public static JobUsageRecord unmarshal(Element elem) throws JAXBException {
+		return context.createUnmarshaller()
+				.unmarshal(new DOMSource(elem), JobUsageRecord.class)
+				.getValue();
+	}
+
+	// TODO: Add signing support
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/src/main/xsd/ur.xsd
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/src/main/xsd/ur.xsd b/taverna-server-usagerecord/src/main/xsd/ur.xsd
new file mode 100644
index 0000000..16344a7
--- /dev/null
+++ b/taverna-server-usagerecord/src/main/xsd/ur.xsd
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema attributeFormDefault="qualified" jaxb:version="2.1"
+	elementFormDefault="qualified" targetNamespace="http://schema.ogf.org/urf/2003/09/urf"
+	xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:urf="http://schema.ogf.org/urf/2003/09/urf"
+	xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+	xsi:schemaLocation="http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd">
+	<xsd:annotation>
+		<!-- Copyright (c) 2003-2008 Open Grid Forum -->
+		<xsd:documentation xml:lang="en">Usage Record Working Group XML Schema definition</xsd:documentation>
+		<xsd:appinfo>
+			<jaxb:schemaBindings>
+				<jaxb:package name="org.ogf.usage.v1_0" />
+			</jaxb:schemaBindings>
+		</xsd:appinfo>
+	</xsd:annotation>
+	<xsd:import namespace="http://www.w3.org/2000/09/xmldsig#"
+		schemaLocation="xmlds.xsd" /> <!-- http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd -->
+	<xsd:complexType name="UsageRecordType">
+		<xsd:sequence>
+			<xsd:element ref="urf:RecordIdentity" />
+			<xsd:element minOccurs="0" ref="urf:JobIdentity" />
+			<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:UserIdentity" />
+			<xsd:element minOccurs="0" ref="urf:JobName" />
+			<xsd:element minOccurs="0" ref="urf:Charge" />
+			<xsd:element ref="urf:Status" />
+			<xsd:choice maxOccurs="unbounded" minOccurs="0">
+				<xsd:annotation>
+					<xsd:documentation>
+						The elements grouped together in this choice may be represented
+						within a usage record multiple times. Each of these appearances
+						must be differentiated by the metric and/or type associated with
+						the element.
+					</xsd:documentation>
+				</xsd:annotation>
+				<xsd:element ref="urf:Disk" />
+				<xsd:element ref="urf:Memory" />
+				<xsd:element ref="urf:Swap" />
+				<xsd:element ref="urf:Network" />
+				<xsd:element ref="urf:TimeDuration" />
+				<xsd:element ref="urf:TimeInstant" />
+				<xsd:element ref="urf:ServiceLevel" />
+			</xsd:choice>
+			<xsd:choice maxOccurs="unbounded" minOccurs="0">
+				<xsd:element minOccurs="0" ref="urf:WallDuration" />
+				<xsd:sequence minOccurs="0">
+					<xsd:element maxOccurs="2" minOccurs="0" ref="urf:CpuDuration" />
+				</xsd:sequence>
+				<xsd:element minOccurs="0" ref="urf:NodeCount" />
+				<xsd:element minOccurs="0" ref="urf:Processors" />
+				<xsd:element minOccurs="0" ref="urf:EndTime" />
+				<xsd:element minOccurs="0" ref="urf:StartTime" />
+				<xsd:element minOccurs="0" ref="urf:MachineName" />
+				<xsd:element minOccurs="0" ref="urf:SubmitHost" />
+				<xsd:element minOccurs="0" ref="urf:Queue" />
+				<xsd:sequence minOccurs="0">
+					<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:ProjectName" />
+				</xsd:sequence>
+				<xsd:sequence minOccurs="0">
+					<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:Host" />
+				</xsd:sequence>
+				<xsd:sequence minOccurs="0">
+					<xsd:choice maxOccurs="unbounded" minOccurs="0">
+						<xsd:element ref="urf:PhaseResource" />
+						<xsd:element ref="urf:VolumeResource" />
+						<xsd:element ref="urf:Resource" />
+						<xsd:element ref="urf:ConsumableResource" />
+					</xsd:choice>
+				</xsd:sequence>
+			</xsd:choice>
+		</xsd:sequence>
+	</xsd:complexType>
+	<xsd:element abstract="true" name="Usage" type="urf:UsageRecordType" />
+	<xsd:element name="UsageRecord" substitutionGroup="urf:Usage"
+		type="urf:UsageRecordType" />
+	<xsd:element name="JobUsageRecord" substitutionGroup="urf:Usage">
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="urf:UsageRecordType" />
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="UsageRecords">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:Usage" />
+			</xsd:sequence>
+		</xsd:complexType>
+	</xsd:element>
+	<!-- Common properties that may be measured with several different metrics 
+		within the same usage record -->
+	<xsd:element name="Network">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attributeGroup ref="urf:intervallicVolume" />
+					<xsd:attribute default="total" ref="urf:metric" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Disk">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attributeGroup ref="urf:intervallicVolume" />
+					<xsd:attribute default="total" ref="urf:metric" use="optional" />
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Memory">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attributeGroup ref="urf:intervallicVolume" />
+					<xsd:attribute default="total" ref="urf:metric" use="optional" />
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Swap">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attributeGroup ref="urf:intervallicVolume" />
+					<xsd:attribute default="total" ref="urf:metric" use="optional" />
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="NodeCount">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attribute default="total" ref="urf:metric" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Processors">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:positiveInteger">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attribute ref="urf:metric" use="optional" />
+					<xsd:attribute name="consumptionRate" type="xsd:float"
+						use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="TimeDuration">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:duration">
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="TimeInstant">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:dateTime">
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="ServiceLevel">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:token">
+					<xsd:attribute ref="urf:type" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<!-- This element should appear at most twice within a usage record, with 
+		differing values for usageType for each appearance -->
+	<xsd:element name="CpuDuration">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:duration">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attribute name="usageType">
+						<xsd:simpleType>
+							<xsd:restriction base="xsd:token">
+								<xsd:enumeration value="user" />
+								<xsd:enumeration value="system" />
+							</xsd:restriction>
+						</xsd:simpleType>
+					</xsd:attribute>
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<!-- These common properties should appear at most once within a usage record, 
+		rather that at most once per metric per usage record -->
+	<xsd:element name="WallDuration">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:duration">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="EndTime">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:dateTime">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="StartTime">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:dateTime">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="MachineName">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="urf:domainNameType">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="SubmitHost">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="urf:domainNameType">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Host">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="urf:domainNameType">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attribute default="false" name="primary" type="xsd:boolean" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Queue">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:string">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="JobName">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:string">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="ProjectName">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:string">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Status">
+		<xsd:annotation>
+			<xsd:documentation>
+				Minimum required set = {Aborted, Completed, Failed,
+				Held, Queued, Started, Suspended}
+			</xsd:documentation>
+		</xsd:annotation>
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:token">
+					<xsd:attribute ref="urf:description" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="Charge">
+		<xsd:complexType>
+			<xsd:simpleContent>
+				<xsd:extension base="xsd:float">
+					<xsd:attribute ref="urf:description" use="optional" />
+					<xsd:attribute ref="urf:unit" use="optional" />
+					<xsd:attribute name="formula" type="xsd:string" use="optional" />
+				</xsd:extension>
+			</xsd:simpleContent>
+		</xsd:complexType>
+	</xsd:element>
+	<!-- identity elements -->
+	<xsd:element name="JobIdentity">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element minOccurs="0" name="GlobalJobId" type="xsd:string" />
+				<xsd:element minOccurs="0" name="LocalJobId" type="xsd:string" />
+				<xsd:sequence>
+					<xsd:element maxOccurs="unbounded" minOccurs="0"
+						name="ProcessId" type="xsd:string" />
+				</xsd:sequence>
+			</xsd:sequence>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="UserIdentity">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element minOccurs="0" name="LocalUserId" type="xsd:string" />
+				<xsd:element minOccurs="0" name="GlobalUserName" type="xsd:string" />
+				<xsd:element minOccurs="0" ref="ds:KeyInfo" />
+			</xsd:sequence>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="RecordIdentity">
+		<xsd:complexType>
+			<xsd:sequence minOccurs="0">
+				<xsd:element ref="ds:KeyInfo" />
+			</xsd:sequence>
+			<xsd:attribute name="recordId" type="xsd:token" use="required" />
+			<xsd:attribute name="createTime" type="xsd:dateTime" use="optional" />
+		</xsd:complexType>
+	</xsd:element>
+	<!-- Extensibility Framework -->
+	<xsd:element name="Resource" type="urf:ResourceType" />
+	<xsd:element name="ConsumableResource" type="urf:ConsumableResourceType" />
+	<xsd:element name="PhaseResource">
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="urf:ConsumableResourceType">
+					<xsd:attribute ref="urf:phaseUnit" use="optional" />
+				</xsd:extension>
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+	<xsd:element name="VolumeResource">
+		<xsd:complexType>
+			<xsd:complexContent>
+				<xsd:extension base="urf:ConsumableResourceType">
+					<xsd:attribute ref="urf:storageUnit" use="optional" />
+				</xsd:extension>
+			</xsd:complexContent>
+		</xsd:complexType>
+	</xsd:element>
+	<!-- Create a generic consumable resource. Carries the units attribute -->
+	<xsd:complexType name="ConsumableResourceType">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:float">
+				<xsd:attribute name="units" type="xsd:string" use="optional" />
+				<xsd:attribute ref="urf:description" use="optional" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+	<!-- Create a generic resource type -->
+	<xsd:complexType name="ResourceType">
+		<xsd:simpleContent>
+			<xsd:extension base="xsd:string">
+				<xsd:attribute ref="urf:description" use="optional" />
+			</xsd:extension>
+		</xsd:simpleContent>
+	</xsd:complexType>
+	<!-- Global Attribute Definitions -->
+	<xsd:attribute name="description" type="xsd:string" />
+	<!-- Units of measure attribute definitions -->
+	<xsd:attribute name="unit" type="xsd:token" />
+	<xsd:attribute name="storageUnit">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:token">
+				<xsd:enumeration value="b" />
+				<xsd:enumeration value="B" />
+				<xsd:enumeration value="KB" />
+				<xsd:enumeration value="MB" />
+				<xsd:enumeration value="GB" />
+				<xsd:enumeration value="PB" />
+				<xsd:enumeration value="EB" />
+				<xsd:enumeration value="Kb" />
+				<xsd:enumeration value="Mb" />
+				<xsd:enumeration value="Gb" />
+				<xsd:enumeration value="Pb" />
+				<xsd:enumeration value="Eb" />
+			</xsd:restriction>
+		</xsd:simpleType>
+	</xsd:attribute>
+	<xsd:attribute name="phaseUnit" type="xsd:duration" />
+	<xsd:attributeGroup name="intervallicVolume">
+		<xsd:attribute ref="urf:storageUnit" use="optional" />
+		<xsd:attribute ref="urf:phaseUnit" use="optional" />
+	</xsd:attributeGroup>
+	<!-- End units attributes -->
+	<xsd:attribute name="metric" type="xsd:token" />
+	<xsd:attribute name="type" type="xsd:token" />
+	<!-- Simple type definitions used to constrain values of attributes -->
+	<xsd:simpleType name="domainNameType">
+		<xsd:restriction base="xsd:string">
+			<xsd:pattern
+				value="([a-zA-Z0-9][a-zA-Z0-9'\-']*[a-zA-Z0-9]\.)*([a-zA-Z0-9][a-zA-Z0-9'\-']*[a-zA-Z0-9])?" />
+			<xsd:maxLength value="255" />
+		</xsd:restriction>
+	</xsd:simpleType>
+</xsd:schema> 
+  
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/src/main/xsd/xmlds.xsd
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/src/main/xsd/xmlds.xsd b/taverna-server-usagerecord/src/main/xsd/xmlds.xsd
new file mode 100644
index 0000000..c3421c4
--- /dev/null
+++ b/taverna-server-usagerecord/src/main/xsd/xmlds.xsd
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE schema
+  PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"
+ [
+   <!ATTLIST schema 
+     xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
+   <!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
+   <!ENTITY % p ''>
+   <!ENTITY % s ''>
+  ]>
+
+<!-- Schema for XML Signatures
+    http://www.w3.org/2000/09/xmldsig#
+    $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
+
+    Copyright 2001 The Internet Society and W3C (Massachusetts Institute
+    of Technology, Institut National de Recherche en Informatique et en
+    Automatique, Keio University). All Rights Reserved.
+    http://www.w3.org/Consortium/Legal/
+
+    This document is governed by the W3C Software License [1] as described
+    in the FAQ [2].
+
+    [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+    [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+-->
+
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+        xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+        targetNamespace="http://www.w3.org/2000/09/xmldsig#"
+        version="0.1" elementFormDefault="qualified"> 
+
+<!-- Basic Types Defined for Signatures -->
+
+<simpleType name="CryptoBinary">
+  <restriction base="base64Binary">
+  </restriction>
+</simpleType>
+
+<!-- Start Signature -->
+
+<element name="Signature" type="ds:SignatureType"/>
+<complexType name="SignatureType">
+  <sequence> 
+    <element ref="ds:SignedInfo"/> 
+    <element ref="ds:SignatureValue"/> 
+    <element ref="ds:KeyInfo" minOccurs="0"/> 
+    <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 
+  </sequence>  
+  <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+  <element name="SignatureValue" type="ds:SignatureValueType"/> 
+  <complexType name="SignatureValueType">
+    <simpleContent>
+      <extension base="base64Binary">
+        <attribute name="Id" type="ID" use="optional"/>
+      </extension>
+    </simpleContent>
+  </complexType>
+
+<!-- Start SignedInfo -->
+
+<element name="SignedInfo" type="ds:SignedInfoType"/>
+<complexType name="SignedInfoType">
+  <sequence> 
+    <element ref="ds:CanonicalizationMethod"/> 
+    <element ref="ds:SignatureMethod"/> 
+    <element ref="ds:Reference" maxOccurs="unbounded"/> 
+  </sequence>  
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+  <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/> 
+  <complexType name="CanonicalizationMethodType" mixed="true">
+    <sequence>
+      <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
+      <!-- (0,unbounded) elements from (1,1) namespace -->
+    </sequence>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+  <element name="SignatureMethod" type="ds:SignatureMethodType"/>
+  <complexType name="SignatureMethodType" mixed="true">
+    <sequence>
+      <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
+      <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+      <!-- (0,unbounded) elements from (1,1) external namespace -->
+    </sequence>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+<!-- Start Reference -->
+
+<element name="Reference" type="ds:ReferenceType"/>
+<complexType name="ReferenceType">
+  <sequence> 
+    <element ref="ds:Transforms" minOccurs="0"/> 
+    <element ref="ds:DigestMethod"/> 
+    <element ref="ds:DigestValue"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+  <attribute name="URI" type="anyURI" use="optional"/> 
+  <attribute name="Type" type="anyURI" use="optional"/> 
+</complexType>
+
+  <element name="Transforms" type="ds:TransformsType"/>
+  <complexType name="TransformsType">
+    <sequence>
+      <element ref="ds:Transform" maxOccurs="unbounded"/>  
+    </sequence>
+  </complexType>
+
+  <element name="Transform" type="ds:TransformType"/>
+  <complexType name="TransformType" mixed="true">
+    <choice minOccurs="0" maxOccurs="unbounded"> 
+      <any namespace="##other" processContents="lax"/>
+      <!-- (1,1) elements from (0,unbounded) namespaces -->
+      <element name="XPath" type="string"/> 
+    </choice>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+<!-- End Reference -->
+
+<element name="DigestMethod" type="ds:DigestMethodType"/>
+<complexType name="DigestMethodType" mixed="true"> 
+  <sequence>
+    <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+  </sequence>    
+  <attribute name="Algorithm" type="anyURI" use="required"/> 
+</complexType>
+
+<element name="DigestValue" type="ds:DigestValueType"/>
+<simpleType name="DigestValueType">
+  <restriction base="base64Binary"/>
+</simpleType>
+
+<!-- End SignedInfo -->
+
+<!-- Start KeyInfo -->
+
+<element name="KeyInfo" type="ds:KeyInfoType"/> 
+<complexType name="KeyInfoType" mixed="true">
+  <choice maxOccurs="unbounded">     
+    <element ref="ds:KeyName"/> 
+    <element ref="ds:KeyValue"/> 
+    <element ref="ds:RetrievalMethod"/> 
+    <element ref="ds:X509Data"/> 
+    <element ref="ds:PGPData"/> 
+    <element ref="ds:SPKIData"/>
+    <element ref="ds:MgmtData"/>
+    <any processContents="lax" namespace="##other"/>
+    <!-- (1,1) elements from (0,unbounded) namespaces -->
+  </choice>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+  <element name="KeyName" type="string"/>
+  <element name="MgmtData" type="string"/>
+
+  <element name="KeyValue" type="ds:KeyValueType"/> 
+  <complexType name="KeyValueType" mixed="true">
+   <choice>
+     <element ref="ds:DSAKeyValue"/>
+     <element ref="ds:RSAKeyValue"/>
+     <any namespace="##other" processContents="lax"/>
+   </choice>
+  </complexType>
+
+  <element name="RetrievalMethod" type="ds:RetrievalMethodType"/> 
+  <complexType name="RetrievalMethodType">
+    <sequence>
+      <element ref="ds:Transforms" minOccurs="0"/> 
+    </sequence>  
+    <attribute name="URI" type="anyURI"/>
+    <attribute name="Type" type="anyURI" use="optional"/>
+  </complexType>
+
+<!-- Start X509Data -->
+
+<element name="X509Data" type="ds:X509DataType"/> 
+<complexType name="X509DataType">
+  <sequence maxOccurs="unbounded">
+    <choice>
+      <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
+      <element name="X509SKI" type="base64Binary"/>
+      <element name="X509SubjectName" type="string"/>
+      <element name="X509Certificate" type="base64Binary"/>
+      <element name="X509CRL" type="base64Binary"/>
+      <any namespace="##other" processContents="lax"/>
+    </choice>
+  </sequence>
+</complexType>
+
+<complexType name="X509IssuerSerialType"> 
+  <sequence> 
+    <element name="X509IssuerName" type="string"/> 
+    <element name="X509SerialNumber" type="integer"/> 
+  </sequence>
+</complexType>
+
+<!-- End X509Data -->
+
+<!-- Begin PGPData -->
+
+<element name="PGPData" type="ds:PGPDataType"/> 
+<complexType name="PGPDataType"> 
+  <choice>
+    <sequence>
+      <element name="PGPKeyID" type="base64Binary"/> 
+      <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/> 
+      <any namespace="##other" processContents="lax" minOccurs="0"
+       maxOccurs="unbounded"/>
+    </sequence>
+    <sequence>
+      <element name="PGPKeyPacket" type="base64Binary"/> 
+      <any namespace="##other" processContents="lax" minOccurs="0"
+       maxOccurs="unbounded"/>
+    </sequence>
+  </choice>
+</complexType>
+
+<!-- End PGPData -->
+
+<!-- Begin SPKIData -->
+
+<element name="SPKIData" type="ds:SPKIDataType"/> 
+<complexType name="SPKIDataType">
+  <sequence maxOccurs="unbounded">
+    <element name="SPKISexp" type="base64Binary"/>
+    <any namespace="##other" processContents="lax" minOccurs="0"/>
+  </sequence>
+</complexType> 
+
+<!-- End SPKIData -->
+
+<!-- End KeyInfo -->
+
+<!-- Start Object (Manifest, SignatureProperty) -->
+
+<element name="Object" type="ds:ObjectType"/> 
+<complexType name="ObjectType" mixed="true">
+  <sequence minOccurs="0" maxOccurs="unbounded">
+    <any namespace="##any" processContents="lax"/>
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+  <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
+  <attribute name="Encoding" type="anyURI" use="optional"/> 
+</complexType>
+
+<element name="Manifest" type="ds:ManifestType"/> 
+<complexType name="ManifestType">
+  <sequence>
+    <element ref="ds:Reference" maxOccurs="unbounded"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+<element name="SignatureProperties" type="ds:SignaturePropertiesType"/> 
+<complexType name="SignaturePropertiesType">
+  <sequence>
+    <element ref="ds:SignatureProperty" maxOccurs="unbounded"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+   <element name="SignatureProperty" type="ds:SignaturePropertyType"/> 
+   <complexType name="SignaturePropertyType" mixed="true">
+     <choice maxOccurs="unbounded">
+       <any namespace="##other" processContents="lax"/>
+       <!-- (1,1) elements from (1,unbounded) namespaces -->
+     </choice>
+     <attribute name="Target" type="anyURI" use="required"/> 
+     <attribute name="Id" type="ID" use="optional"/> 
+   </complexType>
+
+<!-- End Object (Manifest, SignatureProperty) -->
+
+<!-- Start Algorithm Parameters -->
+
+<simpleType name="HMACOutputLengthType">
+  <restriction base="integer"/>
+</simpleType>
+
+<!-- Start KeyValue Element-types -->
+
+<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
+<complexType name="DSAKeyValueType">
+  <sequence>
+    <sequence minOccurs="0">
+      <element name="P" type="ds:CryptoBinary"/>
+      <element name="Q" type="ds:CryptoBinary"/>
+    </sequence>
+    <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
+    <element name="Y" type="ds:CryptoBinary"/>
+    <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
+    <sequence minOccurs="0">
+      <element name="Seed" type="ds:CryptoBinary"/>
+      <element name="PgenCounter" type="ds:CryptoBinary"/>
+    </sequence>
+  </sequence>
+</complexType>
+
+<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
+<complexType name="RSAKeyValueType">
+  <sequence>
+    <element name="Modulus" type="ds:CryptoBinary"/> 
+    <element name="Exponent" type="ds:CryptoBinary"/> 
+  </sequence>
+</complexType> 
+
+<!-- End KeyValue Element-types -->
+
+<!-- End Signature -->
+
+</schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-usagerecord/src/test/java/TestUR.java
----------------------------------------------------------------------
diff --git a/taverna-server-usagerecord/src/test/java/TestUR.java b/taverna-server-usagerecord/src/test/java/TestUR.java
new file mode 100644
index 0000000..42e9000
--- /dev/null
+++ b/taverna-server-usagerecord/src/test/java/TestUR.java
@@ -0,0 +1,120 @@
+import static java.lang.Runtime.getRuntime;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.JAXBIntrospector;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.ogf.usage.JobUsageRecord;
+import org.ogf.usage.v1_0.Charge;
+import org.ogf.usage.v1_0.CpuDuration;
+import org.ogf.usage.v1_0.Disk;
+import org.ogf.usage.v1_0.EndTime;
+import org.ogf.usage.v1_0.Host;
+import org.ogf.usage.v1_0.JobIdentity;
+import org.ogf.usage.v1_0.JobName;
+import org.ogf.usage.v1_0.MachineName;
+import org.ogf.usage.v1_0.Memory;
+import org.ogf.usage.v1_0.Network;
+import org.ogf.usage.v1_0.NodeCount;
+import org.ogf.usage.v1_0.PhaseResource;
+import org.ogf.usage.v1_0.Processors;
+import org.ogf.usage.v1_0.ProjectName;
+import org.ogf.usage.v1_0.Queue;
+import org.ogf.usage.v1_0.RecordIdentity;
+import org.ogf.usage.v1_0.ServiceLevel;
+import org.ogf.usage.v1_0.StartTime;
+import org.ogf.usage.v1_0.Status;
+import org.ogf.usage.v1_0.SubmitHost;
+import org.ogf.usage.v1_0.Swap;
+import org.ogf.usage.v1_0.TimeDuration;
+import org.ogf.usage.v1_0.TimeInstant;
+import org.ogf.usage.v1_0.UserIdentity;
+import org.ogf.usage.v1_0.VolumeResource;
+import org.ogf.usage.v1_0.WallDuration;
+
+public class TestUR {
+	SchemaOutputResolver sink;
+	StringWriter writer;
+
+	String result() {
+		return writer.toString();
+	}
+
+	@Before
+	public void setUp() throws Exception {
+		writer = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(writer);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+		Assert.assertNull(null);// Shut up, Eclipse!
+		Assert.assertEquals("", result());
+	}
+
+	@Test
+	public void testSchema() throws JAXBException, IOException {
+		JAXBContext.newInstance(JobUsageRecord.class).generateSchema(sink);
+		Assert.assertNotSame("", result());
+	}
+
+	@Test
+	public void testSchemaCompleteness() throws JAXBException, DatatypeConfigurationException {
+		JAXBIntrospector info = JAXBContext.newInstance(JobUsageRecord.class).createJAXBIntrospector();
+		Assert.assertTrue(info.isElement(new Charge()));
+		Assert.assertTrue(info.isElement(new CpuDuration()));
+		Assert.assertTrue(info.isElement(new Disk()));
+		Assert.assertTrue(info.isElement(new EndTime()));
+		Assert.assertTrue(info.isElement(new Host()));
+		Assert.assertTrue(info.isElement(new JobIdentity()));
+		Assert.assertTrue(info.isElement(new JobName()));
+		Assert.assertTrue(info.isElement(new JobUsageRecord()));
+		Assert.assertTrue(info.isElement(new MachineName()));
+		Assert.assertTrue(info.isElement(new Memory()));
+		Assert.assertTrue(info.isElement(new Network()));
+		Assert.assertTrue(info.isElement(new NodeCount()));
+		Assert.assertTrue(info.isElement(new PhaseResource()));
+		Assert.assertTrue(info.isElement(new Processors()));
+		Assert.assertTrue(info.isElement(new ProjectName()));
+		Assert.assertTrue(info.isElement(new Queue()));
+		Assert.assertTrue(info.isElement(new RecordIdentity()));
+		Assert.assertTrue(info.isElement(new ServiceLevel()));
+		Assert.assertTrue(info.isElement(new StartTime()));
+		Assert.assertTrue(info.isElement(new Status()));
+		Assert.assertTrue(info.isElement(new SubmitHost()));
+		Assert.assertTrue(info.isElement(new Swap()));
+		Assert.assertTrue(info.isElement(new TimeDuration()));
+		Assert.assertTrue(info.isElement(new TimeInstant()));
+		Assert.assertTrue(info.isElement(new UserIdentity()));
+		Assert.assertTrue(info.isElement(new VolumeResource()));
+		Assert.assertTrue(info.isElement(new WallDuration()));
+	}
+
+	@Test
+	public void testGenerate() throws DatatypeConfigurationException,
+			JAXBException {
+		JobUsageRecord ur = new JobUsageRecord();
+		ur.setStatus("Completed");
+		ur.addWallDuration(1000 * 65);
+		ur.addHost("localhost");
+		ur.addMemory(getRuntime().totalMemory() - getRuntime().freeMemory()).setType("vm");
+
+		String record = ur.marshal();
+		Assert.assertNotSame("", record);
+		//System.out.println(record);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/.gitignore
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/.gitignore b/taverna-server-webapp/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/taverna-server-webapp/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/pom.xml b/taverna-server-webapp/pom.xml
new file mode 100644
index 0000000..f4cf0ef
--- /dev/null
+++ b/taverna-server-webapp/pom.xml
@@ -0,0 +1,889 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-webapp</artifactId>
+	<packaging>war</packaging>
+	<name>Apache Taverna Server Web Application Core</name>
+	<description>This is the implementation of the web-app that provides the Taverna Server with its SOAP and REST faces. It relies on the worker process to handle the actual launching of workflow runs.</description>
+
+	<properties>
+		<version.cxf>2.7.7</version.cxf>
+		<version.spring>3.2.5.RELEASE</version.spring>
+		<version.spring-security>3.1.4.RELEASE</version.spring-security>
+		<version.asm>3.3.1</version.asm>
+		<version.smack>3.2.1</version.smack>
+		<version.jdoapi>3.0.1</version.jdoapi>
+		<forker.module>taverna-server-unix-forker</forker.module>
+		<util.dir>${project.build.directory}/${project.build.finalName}/WEB-INF/classes/util</util.dir>
+		<cmdline.dir>${util.dir}/taverna-commandline-${edition.commandline}-${version.commandline}</cmdline.dir>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.cxf</groupId>
+			<artifactId>cxf-rt-frontend-jaxws</artifactId>
+			<version>${version.cxf}</version>
+			<exclusions>
+				<exclusion>
+					<artifactId>jaxb-impl</artifactId>
+					<groupId>com.sun.xml.bind</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.cxf</groupId>
+			<artifactId>cxf-rt-frontend-jaxrs</artifactId>
+			<version>${version.cxf}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.cxf</groupId>
+			<artifactId>cxf-rt-transports-http</artifactId>
+			<version>${version.cxf}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-logging</groupId>
+			<artifactId>commons-logging</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-aop</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-core</artifactId>
+			<version>${version.spring-security}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-web</artifactId>
+			<version>${version.spring-security}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-config</artifactId>
+			<version>${version.spring-security}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${version.spring}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId><!--$NO-MVN-MAN-VER$-->
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-port-description</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-runinterface</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-usagerecord</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-worker</artifactId>
+			<version>${project.parent.version}</version>
+			<classifier>jar-with-dependencies</classifier>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>${forker.module}</artifactId>
+			<version>${project.parent.version}</version>
+			<classifier>jar-with-dependencies</classifier>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-rmidaemon</artifactId>
+			<version>${project.parent.version}</version>
+			<classifier>jar-with-dependencies</classifier>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<!--
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-annotations</artifactId>
+			<version>3.4.0.GA</version>
+			<scope>compile</scope>
+		</dependency>
+		-->
+		<!--
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-validator</artifactId>
+			<version>4.0.2.GA</version>
+			<scope>compile</scope>
+		</dependency>
+		-->
+		<dependency>
+			<groupId>org.apache.derby</groupId>
+			<artifactId>derby</artifactId>
+			<version>10.10.1.1</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-dbcp</groupId>
+			<artifactId>commons-dbcp</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.jdo</groupId>
+			<artifactId>jdo-api</artifactId>
+			<version>3.0.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.datanucleus</groupId>
+			<artifactId>datanucleus-api-jdo</artifactId>
+			<version>[3.2.0, 3.2.99)</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.datanucleus</groupId>
+			<artifactId>datanucleus-core</artifactId>
+			<version>3.2.10</version>
+		</dependency>
+		<dependency>
+			<groupId>org.datanucleus</groupId>
+			<artifactId>datanucleus-rdbms</artifactId>
+			<version>[3.2.0, 3.2.99)</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.jdo</groupId>
+			<artifactId>jdo2-core</artifactId>
+			<version>2.0</version>
+		</dependency>
+		<dependency>
+			<groupId>joda-time</groupId>
+			<artifactId>joda-time</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.mime-util</groupId>
+			<artifactId>mime-util</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.twitter4j</groupId>
+			<artifactId>twitter4j-core</artifactId>
+			<version>[3.0,)</version>
+		</dependency>
+		<dependency>
+			<groupId>cglib</groupId>
+			<artifactId>cglib</artifactId>
+			<version>3.0</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjrt</artifactId>
+			<version>1.7.4</version>
+		</dependency>
+		<dependency>
+			<groupId>org.igniterealtime.smack</groupId>
+			<artifactId>smack</artifactId>
+			<version>${version.smack}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.igniterealtime.smack</groupId>
+			<artifactId>smackx</artifactId>
+			<version>${version.smack}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>javax.annotation</groupId>
+			<artifactId>jsr250-api</artifactId>
+			<version>1.0</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.abdera</groupId>
+			<artifactId>abdera-core</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.abdera</groupId>
+			<artifactId>abdera-parser</artifactId>
+			<version>1.1.3</version>
+			<scope>runtime</scope>
+			<exclusions>
+				<exclusion>
+					<artifactId>xercesImpl</artifactId>
+					<groupId>xerces</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcprov-jdk15on</artifactId>
+			<version>1.49</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+			<version>${version.spring}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>1.7.4</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.mail</groupId>
+			<artifactId>mail</artifactId>
+			<version>1.4.4</version>
+			<scope>runtime</scope>
+			<exclusions>
+				<exclusion>
+					<groupId>javax.activation</groupId>
+					<artifactId>activation</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.velocity</groupId>
+			<artifactId>velocity</artifactId>
+			<version>1.7</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.cxf</groupId>
+			<artifactId>cxf-rt-rs-extension-providers</artifactId>
+			<version>${version.cxf}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.codehaus.jettison</groupId>
+			<artifactId>jettison</artifactId>
+			<version>1.3.4</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-api</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-t2flow</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-wfbundle</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-compress</artifactId>
+			<version>1.4.1</version>
+		</dependency>
+	</dependencies>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>${project.parent.groupId}</groupId>
+				<artifactId>taverna-server-runinterface</artifactId>
+				<version>${project.parent.version}</version>
+				<scope>compile</scope>
+			</dependency>
+			<dependency>
+				<groupId>asm</groupId>
+				<artifactId>asm</artifactId>
+				<version>${version.asm}</version>
+				<scope>runtime</scope>
+			</dependency>
+			<dependency>
+				<groupId>com.sun.xml.bind</groupId>
+				<artifactId>jaxb-impl</artifactId>
+				<version>2.2.7</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-aop</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-core</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-beans</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-web</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-jdbc</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-tx</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-context</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-expression</artifactId>
+				<version>${version.spring}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.apache.abdera</groupId>
+				<artifactId>abdera-core</artifactId>
+				<version>1.1.3</version>
+			</dependency>
+			<dependency>
+				<groupId>org.codehaus.woodstox</groupId>
+				<artifactId>wstx-asl</artifactId>
+				<version>4.0.6</version>
+			</dependency>
+			<dependency>
+				<groupId>org.apache.geronimo.specs</groupId>
+				<artifactId>geronimo-javamail_1.4_spec</artifactId>
+				<version>1.7.1</version>
+				<scope>provided</scope>
+			</dependency>
+			<dependency>
+				<groupId>org.codehaus.woodstox</groupId>
+				<artifactId>woodstox-core-asl</artifactId>
+				<version>4.2.0</version>
+				<scope>runtime</scope>
+			</dependency>
+			<dependency>
+				<groupId>jaxen</groupId>
+				<artifactId>jaxen</artifactId>
+				<version>1.1.4</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<build>
+		<finalName>TavernaServer.${project.parent.version}</finalName>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.codehaus.mojo</groupId>
+					<artifactId>tomcat-maven-plugin</artifactId>
+					<version>1.1</version>
+					<configuration>
+						<server>deployhost</server>
+						<path>/taverna-server</path>
+					</configuration>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-compiler-plugin</artifactId>
+					<configuration>
+						<encoding>US-ASCII</encoding>
+						<source>1.7</source>
+						<target>1.7</target>
+					</configuration>
+				</plugin>
+				<plugin>
+					<groupId>org.datanucleus</groupId>
+					<artifactId>datanucleus-maven-plugin</artifactId>
+					<version>3.3.0-release</version>
+					<configuration>
+						<jdkLogConfiguration>${project.basedir}/src/build/resources/datanucleus-log.properties</jdkLogConfiguration>
+						<log4jConfiguration>${project.basedir}/src/build/resources/datanucleus_log4j.properties</log4jConfiguration>
+						<verbose>true</verbose>
+					</configuration>
+					<dependencies>
+						<!-- Sucks that I have to say these explicitly -->
+						<dependency>
+							<groupId>org.datanucleus</groupId>
+							<artifactId>datanucleus-core</artifactId>
+							<version>3.2.10</version>
+						</dependency>
+						<dependency>
+							<groupId>org.datanucleus</groupId>
+							<artifactId>datanucleus-enhancer</artifactId>
+							<version>3.1.1</version>
+						</dependency>
+						<dependency>
+							<groupId>org.datanucleus</groupId>
+							<artifactId>datanucleus-api-jdo</artifactId>
+							<version>3.2.5</version>
+						</dependency>
+						<dependency>
+							<groupId>javax.jdo</groupId>
+							<artifactId>jdo-api</artifactId>
+							<version>${version.jdoapi}</version>
+						</dependency>
+					</dependencies>
+				</plugin>
+				<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.apache.maven.plugins</groupId>
+										<artifactId>maven-dependency-plugin</artifactId>
+										<versionRange>[2.0,)</versionRange>
+										<goals>
+											<goal>copy-dependencies</goal>
+											<goal>unpack</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<ignore />
+									</action>
+								</pluginExecution>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.datanucleus</groupId>
+										<artifactId>datanucleus-maven-plugin</artifactId>
+										<versionRange>3.3.0-release</versionRange>
+										<goals>
+											<goal>enhance</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>pl.project13.maven</groupId>
+										<artifactId>git-commit-id-plugin</artifactId>
+										<versionRange>[2.1.4,)</versionRange>
+										<goals>
+											<goal>revision</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.datanucleus</groupId>
+										<artifactId>datanucleus-maven-plugin</artifactId>
+										<versionRange>3.3.0-release</versionRange>
+										<goals>
+											<goal>schema-create</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<ignore />
+									</action>
+								</pluginExecution>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>net.alchim31.maven</groupId>
+										<artifactId>yuicompressor-maven-plugin</artifactId>
+										<versionRange>[1.0.0,)</versionRange>
+										<goals>
+											<goal>compress</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute/>
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+
+		<defaultGoal>package</defaultGoal>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>copy-executable-library-jars</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>copy</goal>
+						</goals>
+						<configuration>
+							<artifactItems>
+								<artifactItem>
+									<groupId>${project.parent.groupId}</groupId>
+									<artifactId>taverna-server-worker</artifactId>
+									<version>${project.parent.version}</version>
+									<classifier>jar-with-dependencies</classifier>
+									<overWrite>false</overWrite>
+									<destFileName>server.worker.jar</destFileName>
+								</artifactItem>
+								<artifactItem>
+									<groupId>${project.parent.groupId}</groupId>
+									<artifactId>${forker.module}</artifactId>
+									<version>${project.parent.version}</version>
+									<classifier>jar-with-dependencies</classifier>
+									<overWrite>false</overWrite>
+									<destFileName>secure.fork.jar</destFileName>
+								</artifactItem>
+								<artifactItem>
+									<groupId>${project.parent.groupId}</groupId>
+									<artifactId>taverna-server-rmidaemon</artifactId>
+									<version>${project.parent.version}</version>
+									<classifier>jar-with-dependencies</classifier>
+									<overWrite>false</overWrite>
+									<destFileName>rmi.daemon.jar</destFileName>
+								</artifactItem>
+							</artifactItems>
+							<outputDirectory>${util.dir}</outputDirectory>
+							<overWriteReleases>false</overWriteReleases>
+							<overWriteSnapshots>true</overWriteSnapshots>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+					<execution>
+						<id>unpack-taverna-commandline</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>unpack</goal>
+						</goals>
+						<configuration>
+							<artifactItems>
+								<artifactItem>
+									<groupId>org.apache.taverna.commandline</groupId>
+									<artifactId>taverna-commandline</artifactId>
+									<version>${taverna.commandline.version}</version>
+									<classifier>bin</classifier>
+									<type>zip</type>
+									<classifier>bin</classifier>
+									<outputDirectory>${util.dir}</outputDirectory>
+								</artifactItem>
+							</artifactItems>
+							<overWriteReleases>false</overWriteReleases>
+							<overWriteSnapshots>true</overWriteSnapshots>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.datanucleus</groupId>
+				<artifactId>datanucleus-maven-plugin</artifactId>
+				<configuration>
+					<fork>false</fork>
+					<metadataIncludes>
+						org/taverna/server/master/*.class,
+						org/taverna/server/master/identity/*.class,
+						org/taverna/server/master/localworker/*.class,
+						org/taverna/server/master/notification/atom/*.class,
+						org/taverna/server/master/usage/*.class,
+						org/taverna/server/master/worker/*.class
+					</metadataIncludes>
+				</configuration>
+				<executions>
+					<execution>
+						<id>enhance</id>
+						<phase>process-classes</phase>
+						<goals>
+							<goal>enhance</goal>
+						</goals>
+					</execution>
+					<!--
+					<execution>
+						<id>gen-db-schema</id>
+						<phase>process-classes</phase>
+						<goals>
+							<goal>schema-create</goal>
+						</goals>
+						<configuration>
+							<completeDdl>true</completeDdl>
+							<ddlFile>${util.dir}/schema.sql</ddlFile>
+						</configuration>
+					</execution>
+					-->
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<encoding>US-ASCII</encoding>
+					<source>1.7</source>
+					<target>1.7</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>pl.project13.maven</groupId>
+				<artifactId>git-commit-id-plugin</artifactId>
+				<version>2.1.4</version>
+				<executions>
+					<execution>
+						<id>buildinfo</id>
+						<phase>generate-resources</phase>
+						<goals>
+							<goal>revision</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<dotGitDirectory>${project.basedir}/../.git</dotGitDirectory>
+					<prefix>git</prefix>
+					<verbose>true</verbose>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<webXml>src/main/webapp/WEB-INF/web-sec.xml</webXml>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-eclipse-plugin</artifactId>
+				<configuration>
+					<additionalProjectnatures>
+						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
+					</additionalProjectnatures>
+					<additionalConfig>
+						<file>
+							<name>.springBeans</name>
+							<content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<beansProjectDescription>
+	<version>1</version>
+	<pluginVersion>3.3.0.201307091516-RELEASE</pluginVersion>
+	<configSuffixes>
+		<configSuffix>xml</configSuffix>
+	</configSuffixes>
+	<enableImports>true</enableImports>
+	<configs>
+		<config>src/main/webapp/WEB-INF/partsecure.xml</config>
+		<config>src/main/webapp/WEB-INF/beans.xml</config>
+		<config>src/main/webapp/WEB-INF/insecure.xml</config>
+		<config>src/main/webapp/WEB-INF/providers.xml</config>
+		<config>src/main/webapp/WEB-INF/secure.xml</config>
+		<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
+	</configs>
+	<configSets>
+		<configSet>
+			<name>Secure Configuration</name>
+			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
+			<incomplete>false</incomplete>
+			<configs>
+				<config>src/main/webapp/WEB-INF/beans.xml</config>
+				<config>src/main/webapp/WEB-INF/providers.xml</config>
+				<config>src/main/webapp/WEB-INF/secure.xml</config>
+				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
+			</configs>
+			<profiles>
+			</profiles>
+		</configSet>
+		<configSet>
+			<name>Insecure Configuration</name>
+			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
+			<incomplete>false</incomplete>
+			<configs>
+				<config>src/main/webapp/WEB-INF/beans.xml</config>
+				<config>src/main/webapp/WEB-INF/insecure.xml</config>
+				<config>src/main/webapp/WEB-INF/providers.xml</config>
+				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
+			</configs>
+			<profiles>
+			</profiles>
+		</configSet>
+		<configSet>
+			<name>Semi-Secure Configuration</name>
+			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
+			<incomplete>false</incomplete>
+			<configs>
+				<config>src/main/webapp/WEB-INF/beans.xml</config>
+				<config>src/main/webapp/WEB-INF/providers.xml</config>
+				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
+				<config>src/main/webapp/WEB-INF/partsecure.xml</config>
+			</configs>
+			<profiles>
+			</profiles>
+		</configSet>
+	</configSets>
+</beansProjectDescription>]]></content>
+						</file>
+					</additionalConfig>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>net.alchim31.maven</groupId>
+				<artifactId>yuicompressor-maven-plugin</artifactId>
+				<version>1.4.0</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>compress</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<excludes>
+						<exclude>**/*.min.js</exclude>
+					</excludes>
+					<nosuffix>true</nosuffix>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>override-executeworkflow-scripts</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>copy-resources</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${cmdline.dir}</outputDirectory>
+							<resources>
+								<resource>
+									<directory>src/main/replacementscripts</directory>
+									<filtering>false</filtering>
+								</resource>
+							</resources>
+							<overwrite>true</overwrite>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>exec-maven-plugin</artifactId>
+				<version>1.2.1</version>
+				<executions>
+					<execution>
+						<id>improve-registry-coverage</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>exec</goal>
+						</goals>
+						<configuration>
+							<executable>/bin/sh</executable>
+							<workingDirectory>${cmdline.dir}</workingDirectory>
+							<environmentVariables>
+								<RAVEN_APPHOME>${cmdline.dir}</RAVEN_APPHOME>
+							</environmentVariables>
+							<arguments>
+								<argument>./executeworkflow.sh</argument>
+								<argument>-help</argument>
+							</arguments>
+							<outputFile>/dev/null</outputFile>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+		<resources>
+			<resource>
+				<directory>src/main/resources</directory>
+				<filtering>true</filtering>
+			</resource>
+			<resource>
+				<directory>src/main/webapp</directory>
+				<filtering>false</filtering>
+			</resource>
+		</resources>
+	</build>
+
+	<profiles>
+		<profile>
+			<id>unix</id>
+			<properties>
+				<forker.module>taverna-server-unix-forker</forker.module>
+			</properties>
+		</profile>
+		<profile>
+			<id>win</id>
+			<properties>
+				<!-- This doesn't exist yet. -->
+				<forker.module>taverna-server-win-forker</forker.module>
+			</properties>
+		</profile>
+		<profile>
+			<id>nosec</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-war-plugin</artifactId>
+						<configuration>
+							<webXml>src/main/webapp/WEB-INF/web-nosec.xml</webXml>
+						</configuration>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+		<profile>
+			<id>partsec</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-war-plugin</artifactId>
+						<configuration>
+							<webXml>src/main/webapp/WEB-INF/web-partsec.xml</webXml>
+						</configuration>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/build/resources/datanucleus_log4j.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/build/resources/datanucleus_log4j.properties b/taverna-server-webapp/src/build/resources/datanucleus_log4j.properties
new file mode 100644
index 0000000..6707f55
--- /dev/null
+++ b/taverna-server-webapp/src/build/resources/datanucleus_log4j.properties
@@ -0,0 +1,4 @@
+log4j.rootLogger=info, R 
+log4j.appender.R=org.apache.log4j.ConsoleAppender
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
new file mode 100644
index 0000000..f5259bd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
@@ -0,0 +1,292 @@
+/*
+ * 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.getMimeType;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.common.Uri.secure;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+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.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.port_description.AbsentValue;
+import org.taverna.server.port_description.AbstractPortDescription;
+import org.taverna.server.port_description.AbstractValue;
+import org.taverna.server.port_description.ErrorValue;
+import org.taverna.server.port_description.InputDescription;
+import org.taverna.server.port_description.InputDescription.InputPort;
+import org.taverna.server.port_description.LeafValue;
+import org.taverna.server.port_description.ListValue;
+import org.taverna.server.port_description.OutputDescription;
+import org.taverna.server.port_description.OutputDescription.OutputPort;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+
+/**
+ * A class that is used to build descriptions of the contents of a workflow
+ * run's filesystem.
+ * 
+ * @author Donal Fellows
+ */
+public class ContentsDescriptorBuilder {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private FilenameUtils fileUtils;
+	private UriBuilderFactory uriBuilderFactory;
+
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
+		this.uriBuilderFactory = uriBuilderFactory;
+	}
+
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	private Workflow fillInFromWorkflow(TavernaRun run, UriBuilder ub,
+			AbstractPortDescription portDesc) throws IOException {
+		WorkflowBundle bundle = run.getWorkflow().getScufl2Workflow();
+		bundle.getMainWorkflow().getInputPorts();
+		portDesc.fillInBaseData(bundle.getMainWorkflow()
+				.getWorkflowIdentifier().toString(), run.getId(), ub.build());
+		return bundle.getMainWorkflow();
+	}
+
+	/**
+	 * Computes the depth of value in a descriptor.
+	 * 
+	 * @param value
+	 *            The value description to characterise.
+	 * @return Its depth (i.e., the depth of the port outputting the value) or
+	 *         <tt>null</tt> if that is impossible to determine.
+	 */
+	private Integer computeDepth(AbstractValue value) {
+		if (value instanceof ListValue) {
+			int mv = 1;
+			for (AbstractValue v : ((ListValue) value).contents) {
+				Integer d = computeDepth(v);
+				if (d != null && mv <= d)
+					mv = d + 1;
+			}
+			return mv;
+		} else if (value instanceof LeafValue || value instanceof ErrorValue)
+			return 0;
+		else
+			return null;
+	}
+
+	/**
+	 * Build a description of a leaf value.
+	 * 
+	 * @param file
+	 *            The file representing the value.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private LeafValue constructLeafValue(File file)
+			throws FilesystemAccessException {
+		LeafValue v = new LeafValue();
+		v.fileName = file.getFullName();
+		v.byteLength = file.getSize();
+		try {
+			byte[] head = file.getContents(0, 1024);
+			v.contentType = getMimeType(new ByteArrayInputStream(head));
+		} catch (Exception e) {
+			v.contentType = APPLICATION_OCTET_STREAM_TYPE.toString();
+		}
+		return v;
+	}
+
+	/**
+	 * Build a description of an error value.
+	 * 
+	 * @param file
+	 *            The file representing the error.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private ErrorValue constructErrorValue(File file)
+			throws FilesystemAccessException {
+		ErrorValue v = new ErrorValue();
+		v.fileName = file.getFullName();
+		v.byteLength = file.getSize();
+		return v;
+	}
+
+	/**
+	 * Build a description of a list value.
+	 * 
+	 * @param dir
+	 *            The directory representing the list.
+	 * @param ub
+	 *            The factory for URIs.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private ListValue constructListValue(Directory dir, UriBuilder ub)
+			throws FilesystemAccessException {
+		ListValue v = new ListValue();
+		v.length = 0;
+		Set<DirectoryEntry> contents = new HashSet<>(dir.getContents());
+		Iterator<DirectoryEntry> it = contents.iterator();
+		while (it.hasNext())
+			if (!it.next().getName().matches("^[0-9]+([.].*)?$"))
+				it.remove();
+		for (int i = 1; !contents.isEmpty(); i++) {
+			String exact = Integer.toString(i);
+			AbstractValue subval = constructValue(contents, ub, exact);
+			v.contents.add(subval);
+			if (!(subval instanceof AbsentValue)) {
+				v.length = i;
+				String pfx = i + ".";
+				for (DirectoryEntry de : contents)
+					if (de.getName().equals(exact)
+							|| de.getName().startsWith(pfx)) {
+						contents.remove(de);
+						break;
+					}
+			}
+		}
+		return v;
+	}
+
+	/**
+	 * Build a value description.
+	 * 
+	 * @param parentContents
+	 *            The contents of the parent directory.
+	 * @param ub
+	 *            The factory for URIs.
+	 * @param name
+	 *            The name of the value's file/directory representative.
+	 * @return A value descriptor.
+	 * @throws FilesystemAccessException
+	 *             If anything goes wrong.
+	 */
+	private AbstractValue constructValue(
+			Collection<DirectoryEntry> parentContents, UriBuilder ub,
+			String name) throws FilesystemAccessException {
+		String error = name + ".error";
+		String prefix = name + ".";
+		for (DirectoryEntry entry : parentContents) {
+			AbstractValue av;
+			if (entry.getName().equals(error) && entry instanceof File) {
+				av = constructErrorValue((File) entry);
+			} else if (!entry.getName().equals(name)
+					&& !entry.getName().startsWith(prefix))
+				continue;
+			else if (entry instanceof File)
+				av = constructLeafValue((File) entry);
+			else
+				av = constructListValue((Directory) entry, ub);
+			String fullPath = entry.getFullName().replaceFirst("^/", "");
+			av.href = ub.clone().path(fullPath).build();
+			return av;
+		}
+		return new AbsentValue();
+	}
+
+	/**
+	 * Construct a description of the outputs of a workflow run.
+	 * 
+	 * @param run
+	 *            The workflow run whose outputs are to be described.
+	 * @param ui
+	 *            The origin for URIs.
+	 * @return The description, which can be serialized to XML.
+	 * @throws FilesystemAccessException
+	 *             If something goes wrong reading the directories.
+	 * @throws NoDirectoryEntryException
+	 *             If something goes wrong reading the directories.
+	 */
+	public OutputDescription makeOutputDescriptor(TavernaRun run, UriInfo ui)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		OutputDescription descriptor = new OutputDescription();
+		try {
+			UriBuilder ub = getRunUriBuilder(run, ui);
+			Workflow dataflow = fillInFromWorkflow(run, ub, descriptor);
+			Collection<DirectoryEntry> outs = null;
+			ub = ub.path("wd/{path}");
+			for (OutputWorkflowPort output : dataflow.getOutputPorts()) {
+				OutputPort p = descriptor.addPort(output.getName());
+				if (run.getOutputBaclavaFile() == null) {
+					if (outs == null)
+						outs = fileUtils.getDirectory(run, "out").getContents();
+					p.output = constructValue(outs, ub, p.name);
+					p.depth = computeDepth(p.output);
+				}
+			}
+		} catch (IOException e) {
+			log.info("failure in conversion to .scufl2", e);
+		}
+		return descriptor;
+	}
+
+	private UriBuilder getRunUriBuilder(TavernaRun run, UriInfo ui) {
+		if (ui == null)
+			return secure(uriBuilderFactory.getRunUriBuilder(run));
+		else
+			return secure(fromUri(ui.getAbsolutePath().toString()
+					.replaceAll("/(out|in)put/?$", "")));
+	}
+
+	/**
+	 * Constructs input descriptions.
+	 * 
+	 * @param run
+	 *            The run to build for.
+	 * @param ui
+	 *            The mechanism for building URIs.
+	 * @return The description of the <i>expected</i> inputs of the run.
+	 */
+	public InputDescription makeInputDescriptor(TavernaRun run, UriInfo ui) {
+		InputDescription desc = new InputDescription();
+		try {
+			UriBuilder ub = getRunUriBuilder(run, ui);
+			Workflow workflow = fillInFromWorkflow(run, ub, desc);
+			ub = ub.path("input/{name}");
+			for (InputWorkflowPort port : workflow.getInputPorts()) {
+				InputPort in = desc.addPort(port.getName());
+				in.href = ub.build(in.name);
+				try {
+					in.depth = port.getDepth();
+				} catch (NumberFormatException ex) {
+					in.depth = null;
+				}
+			}
+		} catch (IOException e) {
+			log.info("failure in conversion to .scufl2", e);
+		}
+		return desc;
+	}
+}


[37/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
deleted file mode 100644
index 62158bb..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- * 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;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
deleted file mode 100644
index 2b328fd..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.joda.time.format.ISODateTimeFormat.basicDateTime;
-import static org.taverna.server.master.common.Roles.USER;
-import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
-import static org.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
-import static org.taverna.server.master.rest.ContentTypes.JSON;
-import static org.taverna.server.master.rest.ContentTypes.ROBUNDLE;
-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.TavernaServerRunREST.PathNames.DIR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
-import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
-import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
-
-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.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-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.JAXBException;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.joda.time.format.DateTimeFormatter;
-import org.taverna.server.master.common.Namespaces;
-import org.taverna.server.master.common.ProfileList;
-import org.taverna.server.master.common.Status;
-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.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-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.interfaces.Listener;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * This represents how a Taverna Server workflow run looks to a RESTful API.
- * 
- * @author Donal Fellows.
- */
-@Description("This represents how a Taverna Server workflow run looks to a "
-		+ "RESTful API.")
-@RolesAllowed(USER)
-public interface TavernaServerRunREST {
-	/**
-	 * Describes a workflow run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return The description.
-	 */
-	@GET
-	@Path(ROOT)
-	@Description("Describes a workflow run.")
-	@Produces({ XML, JSON })
-	@Nonnull
-	public RunDescription getDescription(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Deletes a workflow run.
-	 * 
-	 * @return An HTTP response to the deletion.
-	 * @throws NoUpdateException
-	 *             If the user may see the handle but may not delete it.
-	 */
-	@DELETE
-	@Path(ROOT)
-	@Description("Deletes a workflow run.")
-	@Nonnull
-	public Response destroy() throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ROOT)
-	@Description("Produces the description of the run.")
-	Response runOptions();
-
-	/**
-	 * Returns the workflow document used to create the workflow run.
-	 * 
-	 * @return The workflow document.
-	 */
-	@GET
-	@Path(WF)
-	@Produces({ T2FLOW, SCUFL2, XML, JSON })
-	@Description("Gives the workflow document used to create the workflow run.")
-	@Nonnull
-	public Workflow getWorkflow();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(WF)
-	@Description("Produces the description of the run workflow.")
-	Response workflowOptions();
-
-	/** Get the workflow name. */
-	@GET
-	@Path(NAME)
-	@Produces(TEXT)
-	@Description("Gives the descriptive name of the workflow run.")
-	@Nonnull
-	public String getName();
-
-	/**
-	 * Set the workflow name.
-	 * 
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to change the workflow.
-	 */
-	@PUT
-	@Path(NAME)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Set the descriptive name of the workflow run. Note that "
-			+ "this value may be arbitrarily truncated by the implementation.")
-	@Nonnull
-	public String setName(String name) throws NoUpdateException;
-
-	/** Produce the workflow name HTTP operations. */
-	@OPTIONS
-	@Path(NAME)
-	@Description("Produces the description of the operations on the run's "
-			+ "descriptive name.")
-	@Nonnull
-	Response nameOptions();
-
-	/**
-	 * Produces the name of the workflow's main profile.
-	 * 
-	 * @return The main profile name, or the empty string if there is no such
-	 *         profile.
-	 */
-	@GET
-	@Path(PROFILE)
-	@Produces(TEXT)
-	@Description("Gives the name of the workflow's main profile, or the empty string if none is defined.")
-	@Nonnull
-	String getMainProfileName();
-
-	/**
-	 * Get a description of the profiles supported by the workflow document used
-	 * to create this run.
-	 * 
-	 * @return A description of the supported profiles.
-	 */
-	@GET
-	@Path(PROFILE)
-	@Produces({ XML, JSON })
-	@Description("Describes what profiles exist on the workflow.")
-	@Nonnull
-	ProfileList getProfiles();
-
-	/** Produce the workflow profile HTTP operations. */
-	@OPTIONS
-	@Path(PROFILE)
-	@Description("Produces the description of the operations on the run's "
-			+ "profile.")
-	@Nonnull
-	Response profileOptions();
-
-	/**
-	 * Returns a resource that represents the workflow run's security
-	 * properties. These may only be accessed by the owner.
-	 * 
-	 * @return The security resource.
-	 * @throws NotOwnerException
-	 *             If the accessing principal isn't the owning principal.
-	 */
-	@Path(SEC)
-	@Description("Access the workflow run's security.")
-	@Nonnull
-	public TavernaServerSecurityREST getSecurity() throws NotOwnerException;
-
-	/**
-	 * Returns the time when the workflow run becomes eligible for automatic
-	 * deletion.
-	 * 
-	 * @return When the run expires.
-	 */
-	@GET
-	@Path(T_EXPIRE)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run becomes eligible for "
-			+ "automatic deletion.")
-	@Nonnull
-	public String getExpiryTime();
-
-	/**
-	 * Sets the time when the workflow run becomes eligible for automatic
-	 * deletion.
-	 * 
-	 * @param expiry
-	 *            When the run will expire.
-	 * @return When the run will actually expire.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to manage the lifetime
-	 *             of the run.
-	 */
-	@PUT
-	@Path(T_EXPIRE)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Sets the time when the workflow run becomes eligible for "
-			+ "automatic deletion.")
-	@Nonnull
-	public String setExpiryTime(@Nonnull String expiry)
-			throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_EXPIRE)
-	@Description("Produces the description of the run expiry.")
-	Response expiryOptions();
-
-	/**
-	 * Returns the time when the workflow run was created.
-	 * 
-	 * @return When the run was first submitted to the server.
-	 */
-	@GET
-	@Path(T_CREATE)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was first submitted "
-			+ "to the server.")
-	@Nonnull
-	public String getCreateTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_CREATE)
-	@Description("Produces the description of the run create time.")
-	Response createTimeOptions();
-
-	/**
-	 * Returns the time when the workflow run was started (through a user-driven
-	 * state change).
-	 * 
-	 * @return When the run was started, or <tt>null</tt>.
-	 */
-	@GET
-	@Path(T_START)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was started, or an "
-			+ "empty string if the run has not yet started.")
-	@Nonnull
-	public String getStartTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_START)
-	@Description("Produces the description of the run start time.")
-	Response startTimeOptions();
-
-	/**
-	 * Returns the time when the workflow run was detected to have finished.
-	 * 
-	 * @return When the run finished, or <tt>null</tt>.
-	 */
-	@GET
-	@Path(T_FINISH)
-	@Produces(TEXT)
-	@Description("Gives the time when the workflow run was first detected as "
-			+ "finished, or an empty string if it has not yet finished "
-			+ "(including if it has never started).")
-	@Nonnull
-	public String getFinishTime();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(T_FINISH)
-	@Description("Produces the description of the run finish time.")
-	Response finishTimeOptions();
-
-	/**
-	 * Gets the current status of the workflow run.
-	 * 
-	 * @return The status code.
-	 */
-	@GET
-	@Path(STATUS)
-	@Produces(TEXT)
-	@Description("Gives the current status of the workflow run.")
-	@Nonnull
-	public String getStatus();
-
-	/**
-	 * Sets the status of the workflow run. This does nothing if the status code
-	 * is the same as the run's current state.
-	 * 
-	 * @param status
-	 *            The new status code.
-	 * @return Description of what status the run is actually in, or a 202 to
-	 *         indicate that things are still changing.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to update the run.
-	 * @throws BadStateChangeException
-	 *             If the state cannot be modified in the manner requested.
-	 */
-	@PUT
-	@Path(STATUS)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Attempts to update the status of the workflow run.")
-	@Nonnull
-	public Response setStatus(@Nonnull String status) throws NoUpdateException,
-			BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STATUS)
-	@Description("Produces the description of the run status.")
-	Response statusOptions();
-
-	/**
-	 * Get the working directory of this workflow run.
-	 * 
-	 * @return A RESTful delegate for the working directory.
-	 */
-	@Path(DIR)
-	@Description("Get the working directory of this workflow run.")
-	@Nonnull
-	public TavernaServerDirectoryREST getWorkingDirectory();
-
-	/**
-	 * Get the event listeners attached to this workflow run.
-	 * 
-	 * @return A RESTful delegate for the list of listeners.
-	 */
-	@Path(LISTEN)
-	@Description("Get the event listeners attached to this workflow run.")
-	@Nonnull
-	public TavernaServerListenersREST getListeners();
-
-	/**
-	 * Get a delegate for working with the inputs to this workflow run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return A RESTful delegate for the inputs.
-	 */
-	@Path(IN)
-	@Description("Get the inputs to this workflow run.")
-	@Nonnull
-	public TavernaServerInputREST getInputs(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Get the output Baclava file for this workflow run.
-	 * 
-	 * @return The filename, or empty string to indicate that the outputs will
-	 *         be written to the <tt>out</tt> directory.
-	 */
-	@GET
-	@Path(OUT)
-	@Produces(TEXT)
-	@Description("Gives the Baclava file where output will be written; empty "
-			+ "means use multiple simple files in the out directory.")
-	@Nonnull
-	public String getOutputFile();
-
-	/**
-	 * Get a description of the outputs.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this operation.
-	 * @return A description of the outputs (higher level than the filesystem).
-	 * @throws BadStateChangeException
-	 *             If the run is in the {@link Status#Initialized Initialized}
-	 *             state.
-	 * @throws FilesystemAccessException
-	 *             If problems occur when accessing the filesystem.
-	 * @throws NoDirectoryEntryException
-	 *             If things are odd in the filesystem.
-	 */
-	@GET
-	@Path(OUT)
-	@Produces({ XML, JSON })
-	@Description("Gives a description of the outputs, as currently understood")
-	@Nonnull
-	public OutputDescription getOutputDescription(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Set the output Baclava file for this workflow run.
-	 * 
-	 * @param filename
-	 *            The Baclava file to use, or empty to make the outputs be
-	 *            written to individual files in the <tt>out</tt> subdirectory
-	 *            of the working directory.
-	 * @return The Baclava file as actually set.
-	 * @throws NoUpdateException
-	 *             If the current user is not permitted to update the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is invalid (starts with <tt>/</tt> or
-	 *             contains a <tt>..</tt> segment).
-	 * @throws BadStateChangeException
-	 *             If the workflow is not in the Initialized state.
-	 */
-	@PUT
-	@Path(OUT)
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Description("Sets the Baclava file where output will be written; empty "
-			+ "means use multiple simple files in the out directory.")
-	@Nonnull
-	public String setOutputFile(@Nonnull String filename)
-			throws NoUpdateException, FilesystemAccessException,
-			BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(OUT)
-	@Description("Produces the description of the run output.")
-	Response outputOptions();
-
-	/**
-	 * Get a handle to the interaction feed.
-	 * 
-	 * @return
-	 */
-	@Path(FEED_URL_DIR)
-	@Description("Access the interaction feed for the workflow run.")
-	@Nonnull
-	InteractionFeedREST getInteractionFeed();
-
-	/**
-	 * @return The stdout for the workflow run, or empty string if the run has
-	 *         not yet started.
-	 * @throws NoListenerException
-	 */
-	@GET
-	@Path(STDOUT)
-	@Description("Return the stdout for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	String getStdout() throws NoListenerException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STDOUT)
-	@Description("Return the stdout for the workflow run.")
-	Response stdoutOptions();
-
-	/**
-	 * @return The stderr for the workflow run, or empty string if the run has
-	 *         not yet started.
-	 * @throws NoListenerException
-	 */
-	@GET
-	@Path(STDERR)
-	@Description("Return the stderr for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	String getStderr() throws NoListenerException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(STDERR)
-	@Description("Return the stderr for the workflow run.")
-	Response stderrOptions();
-
-	/**
-	 * @return The usage record for the workflow run, wrapped in a Response, or
-	 *         "empty content" if the run has not yet finished.
-	 * @throws NoListenerException
-	 * @throws JAXBException
-	 */
-	@GET
-	@Path(USAGE)
-	@Description("Return the usage record for the workflow run.")
-	@Produces(XML)
-	@Nonnull
-	Response getUsage() throws NoListenerException, JAXBException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(USAGE)
-	@Description("Return the usage record for the workflow run.")
-	Response usageOptions();
-
-	/**
-	 * @return The log for the workflow run, or empty string if the run has not
-	 *         yet started.
-	 */
-	@GET
-	@Path(LOG)
-	@Description("Return the log for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	Response getLogContents();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(LOG)
-	@Description("Return the log for the workflow run.")
-	Response logOptions();
-
-	/**
-	 * @return The log for the workflow run, or empty string if the run has not
-	 *         yet started.
-	 */
-	@GET
-	@Path(RUNBUNDLE)
-	@Description("Return the run bundle for the workflow run.")
-	@Produces(ROBUNDLE)
-	@Nonnull
-	Response getRunBundle();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(RUNBUNDLE)
-	@Description("Return the run bundle for the workflow run.")
-	Response runBundleOptions();
-
-	/**
-	 * @return Whether to create the run bundle for the workflow run. Only
-	 *         usefully set-able before the start of the run.
-	 */
-	@GET
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	@Produces(TEXT)
-	@Nonnull
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param provenanceFlag
-	 *            Whether to create the run bundle for the workflow run. Only
-	 *            usefully set-able before the start of the run.
-	 * @return What it was actually set to.
-	 * @throws NoUpdateException 
-	 */
-	@PUT
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Nonnull
-	boolean setGenerateProvenance(boolean provenanceFlag) throws NoUpdateException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(GENERATE_PROVENANCE)
-	@Description("Whether to create the run bundle for the workflow run.")
-	Response generateProvenanceOptions();
-
-	/**
-	 * Factored out path names used in the {@link TavernaServerRunREST}
-	 * interface and related places.
-	 * 
-	 * @author Donal Fellows
-	 */
-	interface PathNames {
-		public static final String ROOT = "/";
-		public static final String WF = "workflow";
-		public static final String DIR = "wd";
-		public static final String NAME = "name";
-		public static final String T_EXPIRE = "expiry";
-		public static final String T_CREATE = "createTime";
-		public static final String T_START = "startTime";
-		public static final String T_FINISH = "finishTime";
-		public static final String STATUS = "status";
-		public static final String IN = "input";
-		public static final String OUT = "output";
-		public static final String PROFILE = "profile";
-		public static final String LISTEN = "listeners";
-		public static final String SEC = "security";
-		public static final String STDOUT = "stdout";
-		public static final String STDERR = "stderr";
-		public static final String USAGE = "usage";
-		public static final String LOG = "log";
-		public static final String RUNBUNDLE = "run-bundle";
-		public static final String GENERATE_PROVENANCE = "generate-provenance";
-	}
-
-	/**
-	 * The description of where everything is in a RESTful view of a workflow
-	 * run. Done with JAXB.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement
-	@XmlType(name = "")
-	public static class RunDescription extends VersionedElement {
-		/** The identity of the owner of the workflow run. */
-		@XmlAttribute(namespace = Namespaces.SERVER_REST)
-		public String owner;
-		/** The description of the expiry. */
-		public Expiry expiry;
-		/** The location of the creation workflow description. */
-		public Uri creationWorkflow;
-		/** The location of the creation time property. */
-		public Uri createTime;
-		/** The location of the start time property. */
-		public Uri startTime;
-		/** The location of the finish time property. */
-		public Uri finishTime;
-		/** The location of the status description. */
-		public Uri status;
-		/** The location of the working directory. */
-		public Uri workingDirectory;
-		/** The location of the inputs. */
-		public Uri inputs;
-		/** The location of the Baclava output. */
-		public Uri output;
-		/** The location of the security context. */
-		public Uri securityContext;
-		/** The list of listeners. */
-		public ListenerList listeners;
-		/** The location of the interaction feed. */
-		public Uri interaction;
-		/** The name of the run. */
-		public Uri name;
-		/** The stdout of the run. */
-		public Uri stdout;
-		/** The stderr of the run. */
-		public Uri stderr;
-		/** The usage record for the run. */
-		public Uri usage;
-		/** The log from the run. */
-		public Uri log;
-		/** The bundle describing the run. */
-		@XmlElement(name = RUNBUNDLE)
-		public Uri runBundle;
-		/** Whether to generate a bundle describing the run. */
-		@XmlElement(name = GENERATE_PROVENANCE)
-		public Uri generateProvenance;
-
-		/**
-		 * How to describe a run's expiry.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class Expiry {
-			/**
-			 * Where to go to read the exiry
-			 */
-			@XmlAttribute(name = "href", namespace = Namespaces.XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI ref;
-			/**
-			 * What the expiry currently is.
-			 */
-			@XmlValue
-			public String timeOfDeath;
-
-			/**
-			 * Make a blank expiry description.
-			 */
-			public Expiry() {
-			}
-
-			private static DateTimeFormatter dtf;
-
-			Expiry(TavernaRun r, UriInfo ui, String path, String... parts) {
-				ref = fromUri(new Uri(ui, true, path, parts).ref).build();
-				if (dtf == null)
-					dtf = basicDateTime();
-				timeOfDeath = dtf.print(r.getExpiry().getTime());
-			}
-		}
-
-		/**
-		 * The description of a list of listeners attached to a run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "")
-		public static class ListenerList extends Uri {
-			/**
-			 * The references to the individual listeners.
-			 */
-			public List<Uri> listener;
-
-			/**
-			 * An empty description of listeners.
-			 */
-			public ListenerList() {
-				listener = new ArrayList<>();
-			}
-
-			/**
-			 * @param r
-			 *            The run whose listeners we're talking about.
-			 * @param ub
-			 *            Uri factory; must've been secured
-			 */
-			private ListenerList(TavernaRun r, UriBuilder ub) {
-				super(ub);
-				listener = new ArrayList<>(r.getListeners().size());
-				UriBuilder pathUB = ub.clone().path("{name}");
-				for (Listener l : r.getListeners())
-					listener.add(new Uri(pathUB.build(l.getName())));
-			}
-
-			/**
-			 * @param run
-			 *            The run whose listeners we're talking about.
-			 * @param ui
-			 *            The source of information about URIs.
-			 * @param path
-			 *            Where we are relative to the URI source.
-			 * @param parts
-			 *            Anything required to fill out the path.
-			 */
-			ListenerList(TavernaRun run, UriInfo ui, String path,
-					String... parts) {
-				this(run, secure(fromUri(new Uri(ui, path, parts).ref)));
-			}
-		}
-
-		/**
-		 * An empty description of a run.
-		 */
-		public RunDescription() {
-		}
-
-		/**
-		 * A description of a particular run.
-		 * 
-		 * @param run
-		 *            The run to describe.
-		 * @param ui
-		 *            The factory for URIs.
-		 */
-		public RunDescription(TavernaRun run, UriInfo ui) {
-			super(true);
-			creationWorkflow = new Uri(ui, WF);
-			expiry = new Expiry(run, ui, T_EXPIRE);
-			status = new Uri(ui, STATUS);
-			workingDirectory = new Uri(ui, DIR);
-			listeners = new ListenerList(run, ui, LISTEN);
-			securityContext = new Uri(ui, SEC);
-			inputs = new Uri(ui, IN);
-			output = new Uri(ui, OUT);
-			createTime = new Uri(ui, T_CREATE);
-			startTime = new Uri(ui, T_START);
-			finishTime = new Uri(ui, T_FINISH);
-			interaction = new Uri(ui, FEED_URL_DIR);
-			name = new Uri(ui, NAME);
-			owner = run.getSecurityContext().getOwner().getName();
-			stdout = new Uri(ui, STDOUT);
-			stderr = new Uri(ui, STDERR);
-			usage = new Uri(ui, USAGE);
-			log = new Uri(ui, LOG);
-			runBundle = new Uri(ui, RUNBUNDLE);
-			generateProvenance = new Uri(ui, GENERATE_PROVENANCE);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java b/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
deleted file mode 100644
index 73000e8..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
+++ /dev/null
@@ -1,775 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest;
-
-import static java.util.Collections.emptyList;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-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 static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
-import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-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.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.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.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Permission;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Uri;
-import org.taverna.server.master.common.VersionedElement;
-import org.taverna.server.master.exceptions.BadStateChangeException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoCredentialException;
-
-/**
- * Manages the security of the workflow run. In general, only the owner of a run
- * may access this resource. Many of these security-related resources may only
- * be changed before the run is set to operating.
- * 
- * @author Donal Fellows
- */
-@RolesAllowed(USER)
-@Description("Manages the security of the workflow run. In general, only the "
-		+ "owner of a run may access this resource.")
-public interface TavernaServerSecurityREST {
-	interface PathNames {
-		final String ROOT = "/";
-		final String OWNER = "owner";
-		final String CREDS = "credentials";
-		final String ONE_CRED = CREDS + "/{id}";
-		final String TRUSTS = "trusts";
-		final String ONE_TRUST = TRUSTS + "/{id}";
-		final String PERMS = "permissions";
-		final String ONE_PERM = PERMS + "/{id}";
-	}
-
-	/**
-	 * Gets a description of the security information supported by the workflow
-	 * run.
-	 * 
-	 * @param ui
-	 *            About the URI used to access this resource.
-	 * @return A description of the security information.
-	 */
-	@GET
-	@Path(ROOT)
-	@Produces({ XML, JSON })
-	@Description("Gives a description of the security information supported "
-			+ "by the workflow run.")
-	@Nonnull
-	Descriptor describe(@Nonnull @Context UriInfo ui);
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ROOT)
-	@Description("Produces the description of the run security.")
-	Response descriptionOptions();
-
-	/**
-	 * Gets the identity of who owns the workflow run.
-	 * 
-	 * @return The name of the owner of the run.
-	 */
-	@GET
-	@Path(OWNER)
-	@Produces(TEXT)
-	@Description("Gives the identity of who owns the workflow run.")
-	@Nonnull
-	String getOwner();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(OWNER)
-	@Description("Produces the description of the run owner.")
-	Response ownerOptions();
-
-	/*
-	 * @PUT @Path("/") @Consumes(ContentTypes.BYTES) @CallCounted @Nonnull
-	 * public void set(@Nonnull InputStream contents, @Nonnull @Context UriInfo
-	 * ui);
-	 */
-
-	/**
-	 * @return A list of credentials supplied to this workflow run.
-	 */
-	@GET
-	@Path(CREDS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of credentials supplied to this workflow run.")
-	@Nonnull
-	CredentialList listCredentials();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(CREDS)
-	@Description("Produces the description of the run credentials' operations.")
-	Response credentialsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_CRED)
-	@Description("Produces the description of one run credential's operations.")
-	Response credentialOptions(@PathParam("id") String id);
-
-	/**
-	 * Describe a particular credential.
-	 * 
-	 * @param id
-	 *            The id of the credential to fetch.
-	 * @return The description of the credential.
-	 * @throws NoCredentialException
-	 *             If the credential doesn't exist.
-	 */
-	@GET
-	@Path(ONE_CRED)
-	@Produces({ XML, JSON })
-	@Description("Describes a particular credential.")
-	@Nonnull
-	CredentialHolder getParticularCredential(@Nonnull @PathParam("id") String id)
-			throws NoCredentialException;
-
-	/**
-	 * Update a particular credential.
-	 * 
-	 * @param id
-	 *            The id of the credential to update.
-	 * @param c
-	 *            The details of the credential to use in the update.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the updated credential.
-	 * @throws InvalidCredentialException
-	 *             If the credential description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@PUT
-	@Path(ONE_CRED)
-	@Consumes({ XML, JSON })
-	@Produces({ XML, JSON })
-	@Description("Updates a particular credential.")
-	@Nonnull
-	CredentialHolder setParticularCredential(
-			@Nonnull @PathParam("id") String id, @Nonnull CredentialHolder c,
-			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Adds a new credential.
-	 * 
-	 * @param c
-	 *            The details of the credential to create.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the created credential.
-	 * @throws InvalidCredentialException
-	 *             If the credential description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@POST
-	@Path(CREDS)
-	@Consumes({ XML, JSON })
-	@Description("Creates a new credential.")
-	@Nonnull
-	Response addCredential(@Nonnull CredentialHolder c,
-			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Deletes all credentials associated with a run.
-	 * 
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(CREDS)
-	@Description("Deletes all credentials.")
-	@Nonnull
-	Response deleteAllCredentials(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException;
-
-	/**
-	 * Deletes one credential associated with a run.
-	 * 
-	 * @param id
-	 *            The identity of the credential to delete.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(ONE_CRED)
-	@Description("Deletes a particular credential.")
-	@Nonnull
-	Response deleteCredential(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(TRUSTS)
-	@Description("Produces the description of the run trusted certificates' "
-			+ "operations.")
-	Response trustsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_TRUST)
-	@Description("Produces the description of one run trusted certificate's "
-			+ "operations.")
-	Response trustOptions(@PathParam("id") String id);
-
-	/**
-	 * @return A list of trusted identities supplied to this workflow run.
-	 */
-	@GET
-	@Path(TRUSTS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of trusted identities supplied to this "
-			+ "workflow run.")
-	@Nonnull
-	TrustList listTrusted();
-
-	/**
-	 * Describe a particular trusted identity.
-	 * 
-	 * @param id
-	 *            The id of the trusted identity to fetch.
-	 * @return The description of the trusted identity.
-	 * @throws NoCredentialException
-	 *             If the trusted identity doesn't exist.
-	 */
-	@GET
-	@Path(ONE_TRUST)
-	@Produces({ XML, JSON })
-	@Description("Describes a particular trusted identity.")
-	@Nonnull
-	Trust getParticularTrust(@Nonnull @PathParam("id") String id)
-			throws NoCredentialException;
-
-	/**
-	 * Update a particular trusted identity.
-	 * 
-	 * @param id
-	 *            The id of the trusted identity to update.
-	 * @param t
-	 *            The details of the trusted identity to use in the update.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the updated trusted identity.
-	 * @throws InvalidCredentialException
-	 *             If the trusted identity description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@PUT
-	@Path(ONE_TRUST)
-	@Consumes({ XML, JSON })
-	@Produces({ XML, JSON })
-	@Description("Updates a particular trusted identity.")
-	@Nonnull
-	Trust setParticularTrust(@Nonnull @PathParam("id") String id,
-			@Nonnull Trust t, @Nonnull @Context UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException;
-
-	/**
-	 * Adds a new trusted identity.
-	 * 
-	 * @param t
-	 *            The details of the trusted identity to create.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return Description of the created trusted identity.
-	 * @throws InvalidCredentialException
-	 *             If the trusted identity description isn't valid.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@POST
-	@Path(TRUSTS)
-	@Consumes({ XML, JSON })
-	@Description("Adds a new trusted identity.")
-	@Nonnull
-	Response addTrust(@Nonnull Trust t, @Nonnull @Context UriInfo ui)
-			throws InvalidCredentialException, BadStateChangeException;
-
-	/**
-	 * Deletes all trusted identities associated with a run.
-	 * 
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(TRUSTS)
-	@Description("Deletes all trusted identities.")
-	@Nonnull
-	Response deleteAllTrusts(@Nonnull @Context UriInfo ui)
-			throws BadStateChangeException;
-
-	/**
-	 * Deletes one trusted identity associated with a run.
-	 * 
-	 * @param id
-	 *            The identity of the trusted identity to delete.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return A characterisation of a successful delete.
-	 * @throws BadStateChangeException
-	 *             If the workflow run is not in the initialising state.
-	 */
-	@DELETE
-	@Path(ONE_TRUST)
-	@Description("Deletes a particular trusted identity.")
-	@Nonnull
-	Response deleteTrust(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(PERMS)
-	@Description("Produces the description of the run permissions' operations.")
-	Response permissionsOptions();
-
-	/** Get an outline of the operations supported. */
-	@OPTIONS
-	@Path(ONE_PERM)
-	@Description("Produces the description of one run permission's operations.")
-	Response permissionOptions(@PathParam("id") String id);
-
-	/**
-	 * @return A list of (non-default) permissions associated with this workflow
-	 *         run.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 */
-	@GET
-	@Path(PERMS)
-	@Produces({ XML, JSON })
-	@Description("Gives a list of all non-default permissions associated with "
-			+ "the enclosing workflow run. By default, nobody has any access "
-			+ "at all except for the owner of the run.")
-	@Nonnull
-	PermissionsDescription describePermissions(@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Describe the particular permission granted to a user.
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be described.
-	 * @return The permission they are granted.
-	 */
-	@GET
-	@Path(ONE_PERM)
-	@Produces(TEXT)
-	@Description("Describes the permission granted to a particular user.")
-	@Nonnull
-	Permission describePermission(@Nonnull @PathParam("id") String id);
-
-	/**
-	 * Update the permission granted to a user.
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be updated. Note
-	 *            that the owner always has full permissions.
-	 * @param perm
-	 *            The permission level to set.
-	 * @return The permission level that has actually been set.
-	 */
-	@PUT
-	@Consumes(TEXT)
-	@Produces(TEXT)
-	@Path(ONE_PERM)
-	@Description("Updates the permissions granted to a particular user.")
-	@Nonnull
-	Permission setPermission(@Nonnull @PathParam("id") String id,
-			@Nonnull Permission perm);
-
-	/**
-	 * Delete the permissions associated with a user, which restores them to the
-	 * default (no access unless they are the owner or have admin privileges).
-	 * 
-	 * @param id
-	 *            The name of the user whose permissions are to be revoked.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return An indication that the delete has been successful (or not).
-	 */
-	@DELETE
-	@Path(ONE_PERM)
-	@Description("Deletes (by resetting to default) the permissions "
-			+ "associated with a particular user.")
-	@Nonnull
-	Response deletePermission(@Nonnull @PathParam("id") String id,
-			@Nonnull @Context UriInfo ui);
-
-	/**
-	 * Manufacture a permission setting for a previously-unknown user.
-	 * 
-	 * @param desc
-	 *            A description of the name of the user and the permission level
-	 *            to grant them.
-	 * @param ui
-	 *            Information about the URI used to access this resource.
-	 * @return An indication that the create has been successful (or not).
-	 */
-	@POST
-	@Path(PERMS)
-	@Consumes({ XML, JSON })
-	@Description("Creates a new assignment of permissions to a particular user.")
-	@Nonnull
-	Response makePermission(@Nonnull PermissionDescription desc,
-			@Nonnull @Context UriInfo ui);
-
-	/**
-	 * A description of the security resources associated with a workflow run.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "securityDescriptor")
-	@XmlType(name = "SecurityDescriptor")
-	public static final class Descriptor extends VersionedElement {
-		/** The identity of the owner of the enclosing workflow run. */
-		@XmlElement
-		public String owner;
-		/** Where to get the permissions on the run. */
-		@XmlElement
-		public Uri permissions;
-
-		/** Characterisation of the credentials attached to the run. */
-		@XmlElement
-		public Credentials credentials;
-		/** Characterisation of the trusted certificates attached to the run. */
-		@XmlElement
-		public Trusts trusts;
-
-		public Descriptor() {
-		}
-
-		/**
-		 * Initialise a description of the security context.
-		 * 
-		 * @param ub
-		 *            How to build URIs.
-		 * @param owner
-		 *            Who owns the context.
-		 * @param credential
-		 *            The credentials associated with the context.
-		 * @param trust
-		 *            The trusted certificates associated with the context.
-		 */
-		public Descriptor(@Nonnull UriBuilder ub, @Nonnull String owner,
-				@Nonnull Credential[] credential, @Nonnull Trust[] trust) {
-			super(true);
-			this.owner = owner;
-			this.permissions = new Uri(ub, PERMS);
-			this.credentials = new Credentials(new Uri(ub, CREDS).ref,
-					credential);
-			this.trusts = new Trusts(new Uri(ub, TRUSTS).ref, trust);
-		}
-
-		/**
-		 * A description of credentials associated with a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "CredentialCollection")
-		public static final class Credentials {
-			/** Reference to the collection of credentials */
-			@XmlAttribute(name = "href", namespace = XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI href;
-			/** Descriptions of the credentials themselves. */
-			@XmlElement
-			public List<CredentialHolder> credential = new ArrayList<>();
-
-			public Credentials() {
-			}
-
-			/**
-			 * Initialise a description of the credentials.
-			 * 
-			 * @param uri
-			 *            the URI of the collection.
-			 * @param credential
-			 *            The credentials in the collection.
-			 */
-			public Credentials(@Nonnull URI uri,
-					@Nonnull Credential[] credential) {
-				this.href = uri;
-				for (Credential c : credential)
-					this.credential.add(new CredentialHolder(c));
-			}
-		}
-
-		/**
-		 * A description of trusted certificates associated with a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlType(name = "TrustCollection")
-		public static final class Trusts {
-			/** Reference to the collection of trusted certs */
-			@XmlAttribute(name = "href", namespace = XLINK)
-			@XmlSchemaType(name = "anyURI")
-			public URI href;
-			/** Descriptions of the trusted certs themselves. */
-			@XmlElement
-			public Trust[] trust;
-
-			public Trusts() {
-			}
-
-			/**
-			 * Initialise a description of the trusted certificates.
-			 * 
-			 * @param uri
-			 *            the URI of the collection.
-			 * @param trust
-			 *            The trusted certificates in the collection.
-			 */
-			public Trusts(@Nonnull URI uri, @Nonnull Trust[] trust) {
-				this.href = uri;
-				this.trust = trust.clone();
-			}
-		}
-	}
-
-	/**
-	 * A container for a credential, used to work around issues with type
-	 * inference in CXF's REST service handling and JAXB.
-	 * 
-	 * @see Credential.KeyPair
-	 * @see Credential.Password
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "credential")
-	@XmlType(name = "Credential")
-	public static final class CredentialHolder {
-		/**
-		 * The credential inside this holder.
-		 */
-		@XmlElements({
-				@XmlElement(name = "keypair", namespace = SERVER, type = Credential.KeyPair.class, required = true),
-				@XmlElement(name = "userpass", namespace = SERVER, type = Credential.Password.class, required = true) })
-		public Credential credential;
-
-		public CredentialHolder() {
-		}
-
-		public CredentialHolder(Credential credential) {
-			this.credential = credential;
-		}
-
-		/**
-		 * Convenience accessor function.
-		 * 
-		 * @return The keypair credential held in this holder.
-		 */
-		@XmlTransient
-		public Credential.KeyPair getKeypair() {
-			return (Credential.KeyPair) this.credential;
-		}
-
-		/**
-		 * Convenience accessor function.
-		 * 
-		 * @return The userpass credential held in this holder.
-		 */
-		@XmlTransient
-		public Credential.Password getUserpass() {
-			return (Credential.Password) this.credential;
-		}
-	}
-
-	/**
-	 * A simple list of credential descriptions.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "credentials")
-	public static final class CredentialList extends VersionedElement {
-		/** The descriptions of the credentials */
-		@XmlElement
-		@Nonnull
-		public List<CredentialHolder> credential = new ArrayList<>();
-
-		public CredentialList() {
-		}
-
-		/**
-		 * Initialise the list of credentials.
-		 * 
-		 * @param credential
-		 *            The descriptions of individual credentials.
-		 */
-		public CredentialList(@Nonnull Credential[] credential) {
-			super(true);
-			for (Credential c : credential)
-				this.credential.add(new CredentialHolder(c));
-		}
-	}
-
-	/**
-	 * A simple list of trusted certificate descriptions.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "trustedIdentities")
-	public static final class TrustList extends VersionedElement {
-		/** The descriptions of the trusted certificates */
-		@XmlElement
-		public Trust[] trust;
-
-		public TrustList() {
-		}
-
-		/**
-		 * Initialise the list of trusted certificates.
-		 * 
-		 * @param trust
-		 *            The descriptions of individual certificates.
-		 */
-		public TrustList(@Nonnull Trust[] trust) {
-			super(true);
-			this.trust = trust.clone();
-		}
-	}
-
-	/**
-	 * A description of the permissions granted to others by the owner of a
-	 * workflow run.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "permissionsDescriptor")
-	public static class PermissionsDescription extends VersionedElement {
-		/**
-		 * A description of the permissions granted to one user by the owner of
-		 * a workflow run.
-		 * 
-		 * @author Donal Fellows
-		 */
-		@XmlRootElement(name = "userPermission")
-		public static class LinkedPermissionDescription extends Uri {
-			/** Who is this granted to? */
-			@XmlElement
-			public String userName;
-			/** What are they granted? */
-			@XmlElement
-			public Permission permission;
-
-			public LinkedPermissionDescription() {
-			}
-
-			/**
-			 * Initialise a description of one user's permissions.
-			 * 
-			 * @param ub
-			 *            How to build the URI to this permission. Already
-			 *            secured.
-			 * @param userName
-			 *            Who this relates to.
-			 * @param permission
-			 *            What permission is granted.
-			 * @param strings
-			 *            Parameters to the URI builder.
-			 */
-			LinkedPermissionDescription(@Nonnull UriBuilder ub,
-					@Nonnull String userName, @Nonnull Permission permission,
-					String... strings) {
-				super(ub, strings);
-				this.userName = userName;
-				this.permission = permission;
-			}
-		}
-
-		/** List of descriptions of permissions. */
-		@XmlElement
-		public List<LinkedPermissionDescription> permission;
-
-		public PermissionsDescription() {
-			permission = emptyList();
-		}
-
-		/**
-		 * Initialise the description of a collection of permissions.
-		 * 
-		 * @param ub
-		 *            How to build URIs to this collection. Must have already
-		 *            been secured.
-		 * @param permissionMap
-		 *            The permissions to describe.
-		 */
-		public PermissionsDescription(@Nonnull UriBuilder ub,
-				@Nonnull Map<String, Permission> permissionMap) {
-			permission = new ArrayList<>();
-			List<String> userNames = new ArrayList<>(permissionMap.keySet());
-			Collections.sort(userNames);
-			for (String user : userNames)
-				permission.add(new LinkedPermissionDescription(ub, user,
-						permissionMap.get(user), user));
-		}
-	}
-
-	/**
-	 * An instruction to update the permissions for a user.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlRootElement(name = "permissionUpdate")
-	public static class PermissionDescription {
-		/** Who to set the permission for? */
-		@XmlElement
-		public String userName;
-		/** What permission to grant them? */
-		@XmlElement
-		public Permission permission;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
deleted file mode 100644
index 8b9c75f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.springframework.security.access.AccessDeniedException;
-
-public class AccessDeniedHandler extends HandlerCore implements
-		ExceptionMapper<AccessDeniedException> {
-	@Override
-	public Response toResponse(AccessDeniedException exception) {
-		return respond(FORBIDDEN, exception);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
deleted file mode 100644
index 254382b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadInputPortNameException;
-
-@Provider
-public class BadInputPortNameHandler extends HandlerCore implements
-		ExceptionMapper<BadInputPortNameException> {
-	@Override
-	public Response toResponse(BadInputPortNameException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
deleted file mode 100644
index 6ded568..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadPropertyValueException;
-
-@Provider
-public class BadPropertyValueHandler extends HandlerCore implements
-		ExceptionMapper<BadPropertyValueException> {
-	@Override
-	public Response toResponse(BadPropertyValueException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
deleted file mode 100644
index 9501923..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.BadStateChangeException;
-
-@Provider
-public class BadStateChangeHandler extends HandlerCore implements
-		ExceptionMapper<BadStateChangeException> {
-	@Override
-	public Response toResponse(BadStateChangeException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
deleted file mode 100644
index 20d9f56..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.taverna.server.master.rest.handler;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonMap;
-import static javax.ws.rs.core.Response.notAcceptable;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Variant;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Document;
-import org.apache.abdera.model.Entry;
-import org.apache.abdera.parser.Parser;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-
-@Provider
-@Produces({ "application/atom+xml", "application/atom+xml;type=entry" })
-@Consumes({ "application/atom+xml", "application/atom+xml;type=entry" })
-public class EntryHandler implements MessageBodyWriter<Entry>,
-		MessageBodyReader<Entry> {
-	private static final String ENC = "UTF-8";
-	private static final MediaType ENTRY = new MediaType("application",
-			"atom+xml", singletonMap("type", "entry"));
-	private static final Variant VARIANT = new Variant(ENTRY, (String) null,
-			ENC);
-	private static final Charset UTF8 = Charset.forName(ENC);
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		parser = abdera.getParser();
-		writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	private Parser parser;
-	private Writer writer;
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Entry.class.isAssignableFrom(type))
-			return false;
-		if (!ENTRY.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
-					"type"));
-		return true;
-	}
-
-	@Override
-	public Entry readFrom(Class<Entry> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		Charset cs = UTF8;
-		try {
-			String charset = mediaType.getParameters().get("charset");
-			if (charset != null)
-				cs = Charset.forName(charset);
-		} catch (IllegalCharsetNameException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("bad charset name").build());
-		} catch (UnsupportedCharsetException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("unsupportd charset name").build());
-		}
-		try {
-			Document<Entry> doc = parser.parse(new InputStreamReader(
-					entityStream, cs));
-			if (!Entry.class.isAssignableFrom(doc.getRoot().getClass())) {
-				throw new WebApplicationException(
-						notAcceptable(asList(VARIANT)).entity(
-								"not really a feed entry").build());
-			}
-			return doc.getRoot();
-		} catch (ClassCastException e) {
-			throw new WebApplicationException(notAcceptable(asList(VARIANT))
-					.entity("not really a feed entry").build());
-
-		}
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Entry.class.isAssignableFrom(type))
-			return false;
-		if (!ENTRY.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
-					"type"));
-		return true;
-	}
-
-	@Override
-	public long getSize(Entry t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Entry t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		httpHeaders.putSingle("Content-Type", ENTRY.toString() + ";charset="
-				+ ENC);
-		writer.writeTo(t, new OutputStreamWriter(entityStream, UTF8));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
deleted file mode 100644
index 7c17f5c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.taverna.server.master.rest.handler;
-
-import static java.util.Collections.singletonMap;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.abdera.Abdera;
-import org.apache.abdera.model.Feed;
-import org.apache.abdera.writer.Writer;
-import org.springframework.beans.factory.annotation.Required;
-
-@Provider
-@Produces({ "application/atom+xml", "application/atom+xml;type=feed" })
-public class FeedHandler implements MessageBodyWriter<Feed> {
-	private static final MediaType FEED = new MediaType("application",
-			"atom+xml", singletonMap("type", "feed"));
-	private static final String ENC = "UTF-8";
-
-	@Required
-	public void setAbdera(Abdera abdera) {
-		writer = abdera.getWriterFactory().getWriter("prettyxml");
-	}
-
-	private Writer writer;
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (!Feed.class.isAssignableFrom(type))
-			return false;
-		if (!FEED.isCompatible(mediaType))
-			return false;
-		if (mediaType.getParameters().containsKey("type"))
-			return "feed".equalsIgnoreCase(mediaType.getParameters()
-					.get("type"));
-		return true;
-	}
-
-	@Override
-	public long getSize(Feed t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Feed t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		httpHeaders.putSingle("Content-Type", FEED.toString() + ";charset="
-				+ ENC);
-		writer.writeTo(t, new OutputStreamWriter(entityStream, ENC));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
deleted file mode 100644
index ab18d73..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.taverna.server.master.rest.handler;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.FileConcatenation;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-public class FileConcatenationHandler implements
-		MessageBodyWriter<FileConcatenation> {
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	@Required
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(FileConcatenation.class);
-	}
-
-	@Override
-	public long getSize(FileConcatenation fc, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return fc.size();
-	}
-
-	@Override
-	public void writeTo(FileConcatenation fc, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException {
-		for (File f : fc)
-			try {
-				byte[] buffer;
-				for (int off = 0; true ; off += buffer.length) {
-					buffer = f.getContents(off, maxChunkSize);
-					if (buffer == null || buffer.length == 0)
-						break;
-					entityStream.write(buffer);
-				}
-			} catch (FilesystemAccessException e) {
-				// Ignore/skip to next file
-			}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
deleted file mode 100644
index 0aeb816..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * How to write out a File object with JAX-RS.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class FileMessageHandler implements MessageBodyWriter<File> {
-	private Log log = getLog("Taverna.Server.Webapp");
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return File.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public long getSize(File t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		try {
-			return t.getSize(); // Is it really raw bytes?
-		} catch (FilesystemAccessException e) {
-			log.info("failed to get file length", e);
-			return -1;
-		}
-	}
-
-	@Override
-	public void writeTo(File t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			int off = 0;
-			while (true) {
-				byte[] buffer = t.getContents(off, maxChunkSize);
-				if (buffer == null || buffer.length == 0)
-					break;
-				entityStream.write(buffer);
-				off += buffer.length;
-			}
-		} catch (FilesystemAccessException e) {
-			throw new IOException("problem when reading file", e);
-		}
-	}
-}


[46/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-execution-delegate/src/test/java/SerializationTest.java
----------------------------------------------------------------------
diff --git a/server-execution-delegate/src/test/java/SerializationTest.java b/server-execution-delegate/src/test/java/SerializationTest.java
deleted file mode 100644
index c4bf0b9..0000000
--- a/server-execution-delegate/src/test/java/SerializationTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.execution_delegate.RemoteExecution.WorkflowReportDocument;
-
-public class SerializationTest {
-	private static final boolean PRINT = true;
-	SchemaOutputResolver sink;
-	StringWriter schema;
-
-	String schema() {
-		return schema.toString();
-	}
-
-	@Before
-	public void init() {
-		schema = new StringWriter();
-		sink = new SchemaOutputResolver() {
-			@Override
-			public Result createOutput(String namespaceUri,
-					String suggestedFileName) throws IOException {
-				StreamResult sr = new StreamResult(schema);
-				sr.setSystemId("/dev/null");
-				return sr;
-			}
-		};
-		assertEquals("", schema());
-	}
-
-	@Test
-	public void testSchemaGeneration() throws JAXBException, IOException {
-		JAXBContext.newInstance(WorkflowReportDocument.class).generateSchema(
-				sink);
-		assertFalse("generated schema must be non-empty", schema().isEmpty());
-		assertTrue(
-				"generated schema must define workflowReport element",
-				schema().contains(
-						"<xs:element name=\"workflowReport\" type=\"WorkflowReport\"/>\n"));
-		if (PRINT)
-			System.out.print(schema());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/.gitignore
----------------------------------------------------------------------
diff --git a/server-port-description/.gitignore b/server-port-description/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/server-port-description/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/pom.xml
----------------------------------------------------------------------
diff --git a/server-port-description/pom.xml b/server-port-description/pom.xml
deleted file mode 100644
index 99582ed..0000000
--- a/server-port-description/pom.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-port-description</artifactId>
-	<name>Apache Taverna Server Workflow Port Descriptor Types</name>
-	<description>The structural types used to describe ports on workflows, as exported by Taverna Server.</description>
-
-	<properties>
-		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-	</properties>
-	<build>
-		<pluginManagement>
-			<plugins>
-				<plugin>
-					<groupId>org.apache.maven.plugins</groupId>
-					<artifactId>maven-eclipse-plugin</artifactId>
-					<configuration>
-						<projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
-					</configuration>
-				</plugin>
-			</plugins>
-		</pluginManagement>
-	</build>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java b/server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
deleted file mode 100644
index 2ea392f..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/AbsentValue.java
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(name = "AbsentValue")
-public class AbsentValue extends AbstractValue {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java b/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
deleted file mode 100644
index e57c4f9..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPort.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlID;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-
-import org.taverna.server.port_description.utils.IntAdapter;
-
-@XmlType(name = "Port")
-public class AbstractPort {
-	@XmlID
-	@XmlAttribute(required = true)
-	public String name;
-
-	@XmlAttribute
-	@XmlSchemaType(name = "int")
-	@XmlJavaTypeAdapter(IntAdapter.class)
-	public Integer depth;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java b/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
deleted file mode 100644
index 7c3fe9a..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractPortDescription.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(name = "PortDescription")
-public abstract class AbstractPortDescription {
-	@XmlAttribute
-	public String workflowId;
-	@XmlAttribute
-	@XmlSchemaType(name = "anyURI")
-	public URI workflowRun;
-	@XmlAttribute
-	public String workflowRunId;
-
-	public void fillInBaseData(String docId, String runId, URI runUrl) {
-		this.workflowId = docId;
-		this.workflowRun = runUrl;
-		this.workflowRunId = runId;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java b/server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
deleted file mode 100644
index 47232c2..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/AbstractValue.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import static org.taverna.server.port_description.Namespaces.XLINK;
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(name = "Value")
-@XmlSeeAlso( { ErrorValue.class, LeafValue.class, ListValue.class, AbsentValue.class })
-public abstract class AbstractValue {
-	@XmlAttribute(namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI href;
-
-	public void setAddress(URI uri, String localAddress) {
-		if (uri.getPath().endsWith("/")) {
-			href = URI.create(uri + "wd/out/" + localAddress);
-		} else {
-			href = URI.create(uri + "/wd/out/" + localAddress);
-		}
-		//about = "out/" + localAddress;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java b/server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
deleted file mode 100644
index 0bb07b4..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/ErrorValue.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-
-import org.taverna.server.port_description.utils.IntAdapter;
-
-@XmlType(name = "ErrorValue")
-public class ErrorValue extends AbstractValue {
-	@XmlAttribute
-	@XmlSchemaType(name = "int")
-	@XmlJavaTypeAdapter(IntAdapter.class)
-	public Integer depth;
-	@XmlAttribute(name = "errorFile")
-	public String fileName;
-	@XmlAttribute(name = "errorByteLength")
-	public Long byteLength;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java b/server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
deleted file mode 100644
index 60b9353..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/InputDescription.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import static org.taverna.server.port_description.Namespaces.XLINK;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * A description of the inputs of a workflow run, as they are currently known
- * about.
- * 
- * @author Donal Fellows.
- */
-@XmlRootElement
-public class InputDescription extends AbstractPortDescription {
-	@XmlElement
-	public List<InputPort> input = new ArrayList<>();
-
-	@XmlType(name = "InputPort")
-	public static class InputPort extends AbstractPort {
-		@XmlAttribute(namespace = XLINK)
-		@XmlSchemaType(name = "anyURI")
-		public URI href;
-	}
-
-	/**
-	 * Add an input port to the list of ports.
-	 * 
-	 * @param name
-	 *            The name of the port to add.
-	 * @return The port (so that its details may be set);
-	 */
-	public InputPort addPort(String name) {
-		InputPort p = new InputPort();
-		p.name = name;
-		input.add(p);
-		return p;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java b/server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
deleted file mode 100644
index 052c0ef..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/LeafValue.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType(name = "LeafValue")
-public class LeafValue extends AbstractValue {
-	@XmlAttribute(name = "contentFile")
-	public String fileName;
-	@XmlAttribute(name = "contentType")
-	public String contentType;
-	@XmlAttribute(name = "contentByteLength")
-	public Long byteLength;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java b/server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
deleted file mode 100644
index b14cdf1..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/ListValue.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-
-import org.taverna.server.port_description.utils.IntAdapter;
-
-@XmlType(name = "ListValue")
-public class ListValue extends AbstractValue {
-	@XmlAttribute
-	@XmlSchemaType(name = "int")
-	@XmlJavaTypeAdapter(IntAdapter.class)
-	public Integer length;
-	@XmlElements({
-			@XmlElement(name = "value", type = LeafValue.class, nillable = false),
-			@XmlElement(name = "list", type = ListValue.class, nillable = false),
-			@XmlElement(name = "error", type = ErrorValue.class, nillable = false),
-			@XmlElement(name = "absent", type = AbsentValue.class, nillable = false) })
-	public List<AbstractValue> contents = new ArrayList<>();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java b/server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
deleted file mode 100644
index 4003cdb..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/Namespaces.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-public interface Namespaces {
-	static final String DATA = "http://ns.taverna.org.uk/2010/port/";
-	static final String RUN = "http://ns.taverna.org.uk/2010/run/";
-	static final String XLINK = "http://www.w3.org/1999/xlink";
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java b/server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
deleted file mode 100644
index 0b94973..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/OutputDescription.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElements;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * A description of the outputs of a workflow run, as they are currently known
- * about.
- * 
- * @author Donal Fellows
- */
-@XmlRootElement(name = "workflowOutputs")
-public class OutputDescription extends AbstractPortDescription {
-	private static final AbsentValue ABSENT_VALUE = new AbsentValue();
-	@XmlElement(name = "output")
-	public List<OutputPort> ports = new ArrayList<>();
-
-	@XmlType(name = "OutputPort")
-	public static class OutputPort extends AbstractPort {
-		@XmlElements({
-				@XmlElement(name = "value", type = LeafValue.class, nillable = false, required = true),
-				@XmlElement(name = "list", type = ListValue.class, nillable = false, required = true),
-				@XmlElement(name = "error", type = ErrorValue.class, nillable = false, required = true),
-				@XmlElement(name = "absent", type = AbsentValue.class, nillable = false, required = true) })
-		public AbstractValue output;
-	}
-
-	/**
-	 * Add an output port to the list of ports.
-	 * 
-	 * @param name
-	 *            The name of the port to add.
-	 * @return The port (so that its value may be set);
-	 */
-	public OutputPort addPort(String name) {
-		OutputPort p = new OutputPort();
-		p.name = name;
-		p.output = ABSENT_VALUE;
-		ports.add(p);
-		return p;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/package-info.java b/server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
deleted file mode 100644
index b1ac2c6..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/package-info.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-@XmlSchema(namespace = DATA, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "run", namespaceURI = RUN) })
-package org.taverna.server.port_description;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.port_description.Namespaces.DATA;
-import static org.taverna.server.port_description.Namespaces.RUN;
-import static org.taverna.server.port_description.Namespaces.XLINK;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java b/server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
deleted file mode 100644
index 8764176..0000000
--- a/server-port-description/src/main/java/org/taverna/server/port_description/utils/IntAdapter.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.port_description.utils;
-
-import static javax.xml.bind.DatatypeConverter.parseInt;
-import static javax.xml.bind.DatatypeConverter.printInt;
-
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-
-/**
- * A type conversion utility for use with JAXB.
- * 
- * @author Donal Fellows
- */
-public class IntAdapter extends XmlAdapter<String, Integer> {
-	@Override
-	public String marshal(Integer value) throws Exception {
-		if (value == null)
-			return null;
-		return printInt(value);
-	}
-
-	@Override
-	public Integer unmarshal(String value) throws Exception {
-		if (value == null)
-			return null;
-		return parseInt(value);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java b/server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
deleted file mode 100644
index c952ec2..0000000
--- a/server-port-description/src/test/java/org/taverna/server/port_description/JaxbSanityTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.taverna.server.port_description;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * This test file ensures that the JAXB bindings will work once deployed instead
- * of mysteriously failing in service.
- * 
- * @author Donal Fellows
- */
-public class JaxbSanityTest {
-	SchemaOutputResolver sink;
-	StringWriter schema;
-
-	String schema() {
-		return schema.toString();
-	}
-
-	private String schemaTest(Class<?>... classes) throws IOException, JAXBException {
-		Assert.assertTrue(schema().isEmpty());
-		JAXBContext.newInstance(classes).generateSchema(sink);
-		Assert.assertFalse(schema().isEmpty());
-		return schema();
-	}
-
-	@Before
-	public void init() {
-		schema = new StringWriter();
-		sink = new SchemaOutputResolver() {
-			@Override
-			public Result createOutput(String namespaceUri,
-					String suggestedFileName) throws IOException {
-				StreamResult sr = new StreamResult(schema);
-				sr.setSystemId("/dev/null");
-				return sr;
-			}
-		};
-	}
-
-	@Test
-	public void testJAXBForInput() throws Exception {
-		schemaTest(InputDescription.InputPort.class);
-	}
-
-	@Test
-	public void testJAXBForInputDescription() throws Exception {
-		schemaTest(InputDescription.class);
-	}
-
-	@Test
-	public void testJAXBForAbsentValue() throws Exception {
-		schemaTest(AbstractValue.class);
-	}
-
-	@Test
-	public void testJAXBForAbstractValue() throws Exception {
-		schemaTest(AbstractValue.class);
-	}
-
-	@Test
-	public void testJAXBForErrorValue() throws Exception {
-		schemaTest(ErrorValue.class);
-	}
-
-	@Test
-	public void testJAXBForLeafValue() throws Exception {
-		schemaTest(LeafValue.class);
-	}
-
-	@Test
-	public void testJAXBForListValue() throws Exception {
-		schemaTest(ListValue.class);
-	}
-
-	@Test
-	public void testJAXBForOutputDescription() throws Exception {
-		schemaTest(OutputDescription.class);
-	}
-
-	@Test
-	public void testJAXBForEverythingAtOnce() throws Exception {
-		schemaTest(AbsentValue.class, AbstractValue.class, ListValue.class,
-				LeafValue.class, ErrorValue.class, OutputDescription.class,
-				InputDescription.InputPort.class, InputDescription.class);
-		// System.out.println(schema());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-rmidaemon/pom.xml
----------------------------------------------------------------------
diff --git a/server-rmidaemon/pom.xml b/server-rmidaemon/pom.xml
deleted file mode 100644
index 0e2a565..0000000
--- a/server-rmidaemon/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-
-	<artifactId>taverna-server-rmidaemon</artifactId>
-	<name>Apache Taverna Server RMI registry daemon</name>
-	<description>Customised RMI registry that supports restricting to localhost.</description>
-
-	<properties>
-		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
-		<mainClass>org.taverna.server.rmidaemon.Registry</mainClass>
-	</properties>
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<configuration>
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<mainClass>${mainClass}</mainClass>
-						</manifest>
-					</archive>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-assembly</id>
-						<phase>package</phase>
-						<goals>
-							<goal>single</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
----------------------------------------------------------------------
diff --git a/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java b/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
deleted file mode 100644
index 4be7579..0000000
--- a/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/Registry.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.taverna.server.rmidaemon;
-
-import static java.lang.System.setProperty;
-import static java.net.InetAddress.getLocalHost;
-import static java.rmi.registry.LocateRegistry.createRegistry;
-import static java.rmi.registry.Registry.REGISTRY_PORT;
-import static java.rmi.server.RMISocketFactory.getDefaultSocketFactory;
-
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.net.ServerSocket;
-import java.rmi.MarshalledObject;
-import java.rmi.server.RMIServerSocketFactory;
-
-/**
- * Special version of <tt>rmiregistry</tt>.
- * 
- * @author Donal Fellows
- */
-public class Registry {
-	/**
-	 * Run a registry. The first optional argument is the port for the registry
-	 * to listen on, and the second optional argument is whether the registry
-	 * should restrict itself to connections from localhost only.
-	 * 
-	 * @param args
-	 *            Arguments to the program.
-	 */
-	public static void main(String... args) {
-		try {
-			if (args.length > 0)
-				port = Integer.parseInt(args[0]);
-		} catch (Exception e) {
-			System.err.println("failed to parse port: " + e.getMessage());
-			System.exit(2);
-		}
-		try {
-			if (args.length > 1)
-				localhostOnly = Boolean.parseBoolean(args[1]);
-		} catch (Exception e) {
-			System.err.println("failed to parse boolean localhost flag: "
-					+ e.getMessage());
-			System.exit(2);
-		}
-		try {
-			Object registryHandle = makeRegistry();
-			try (ObjectOutputStream oos = new ObjectOutputStream(System.out)) {
-				oos.writeObject(registryHandle);
-			}
-		} catch (Exception e) {
-			System.err.println("problem creating registry: " + e.getMessage());
-			System.exit(1);
-		}
-	}
-
-	private static int port = REGISTRY_PORT;
-	private static boolean localhostOnly = false;
-
-	private static MarshalledObject<java.rmi.registry.Registry> makeRegistry() throws IOException {
-		if (!localhostOnly)
-			return new MarshalledObject<>(createRegistry(port));
-		setProperty("java.rmi.server.hostname", "127.0.0.1");
-		return new MarshalledObject<>(createRegistry(port,
-				getDefaultSocketFactory(), new RMIServerSocketFactory() {
-					@Override
-					public ServerSocket createServerSocket(int port)
-							throws IOException {
-						return new ServerSocket(port, 0, getLocalHost());
-					}
-				}));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
----------------------------------------------------------------------
diff --git a/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java b/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
deleted file mode 100644
index 32144b5..0000000
--- a/server-rmidaemon/src/main/java/org/taverna/server/rmidaemon/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * RMI daemon implementation. A variation of an RMI registry.
- * @author Donal Fellows
- */
-package org.taverna.server.rmidaemon;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/.gitignore
----------------------------------------------------------------------
diff --git a/server-runinterface/.gitignore b/server-runinterface/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/server-runinterface/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/pom.xml
----------------------------------------------------------------------
diff --git a/server-runinterface/pom.xml b/server-runinterface/pom.xml
deleted file mode 100644
index efd3763..0000000
--- a/server-runinterface/pom.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-
-	<artifactId>taverna-server-runinterface</artifactId>
-	<name>Apache Taverna Server RMI Interface: Webapp &lt;-&gt; Worker</name>
-	<description>This is the implementation of the RMI interface between the workflow run factory and the web-app service front-end.</description>
-
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/META-INF/MANIFEST.MF b/server-runinterface/src/main/java/META-INF/MANIFEST.MF
deleted file mode 100644
index 5e94951..0000000
--- a/server-runinterface/src/main/java/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,3 +0,0 @@
-Manifest-Version: 1.0
-Class-Path: 
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
deleted file mode 100644
index 9f4bf50..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/IllegalStateTransitionException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that indicates where a change of a workflow run's status is
- * illegal.
- * 
- * @author Donal Fellows
- * @see RemoteSingleRun#setStatus(RemoteStatus)
- */
-@WebFault(name = "IllegalStateTransitionFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
-public class IllegalStateTransitionException extends Exception {
-	private static final long serialVersionUID = 159673249162345L;
-
-	public IllegalStateTransitionException() {
-		this("illegal state transition");
-	}
-
-	public IllegalStateTransitionException(String message) {
-		super(message);
-	}
-
-	public IllegalStateTransitionException(Throwable cause) {
-		this("illegal state transition", cause);
-	}
-
-	public IllegalStateTransitionException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
deleted file mode 100644
index a47d112..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/ImplementationException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import javax.xml.ws.WebFault;
-
-/**
- * Exception that indicates that the implementation has gone wrong in some
- * unexpected way.
- * 
- * @author Donal Fellows
- */
-@WebFault(name = "ImplementationFault", targetNamespace = "http://ns.taverna.org.uk/2010/xml/server/worker/")
-@SuppressWarnings("serial")
-public class ImplementationException extends Exception {
-	public ImplementationException(String message) {
-		super(message);
-	}
-
-	public ImplementationException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
deleted file mode 100644
index 395842a..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.util.Collection;
-
-import javax.annotation.Nonnull;
-
-/**
- * Represents a directory that is the working directory of a workflow run, or a
- * sub-directory of it.
- * 
- * @author Donal Fellows
- * @see RemoteFile
- */
-public interface RemoteDirectory extends RemoteDirectoryEntry {
-	/**
-	 * @return A list of the contents of the directory.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If anything goes wrong with listing the directory.
-	 */
-	@Nonnull
-	public Collection<RemoteDirectoryEntry> getContents()
-			throws RemoteException, IOException;
-
-	/**
-	 * Creates a sub-directory of this directory.
-	 * 
-	 * @param name
-	 *            The name of the sub-directory.
-	 * @return A handle to the newly-created directory.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong with creating the subdirectory.
-	 */
-	@Nonnull
-	public RemoteDirectory makeSubdirectory(@Nonnull String name)
-			throws RemoteException, IOException;
-
-	/**
-	 * Creates an empty file in this directory.
-	 * 
-	 * @param name
-	 *            The name of the file to create.
-	 * @return A handle to the newly-created file.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If anything goes wrong with creating the file.
-	 */
-	@Nonnull
-	public RemoteFile makeEmptyFile(@Nonnull String name)
-			throws RemoteException, IOException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
deleted file mode 100644
index 1e04b44..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteDirectoryEntry.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.io.IOException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.Date;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-/**
- * An entry in a {@link RemoteDirectory} representing a file or sub-directory.
- * 
- * @author Donal Fellows
- * @see RemoteDirectory
- * @see RemoteFile
- */
-public interface RemoteDirectoryEntry extends Remote {
-	/**
-	 * @return The "local" name of the entry. This will never be "<tt>..</tt>"
-	 *         or contain the character "<tt>/</tt>".
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String getName() throws RemoteException;
-
-	/**
-	 * @return The time when the entry was last modified.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public Date getModificationDate() throws RemoteException;
-
-	/**
-	 * Gets the directory containing this directory entry.
-	 * 
-	 * @return A directory handle, or <tt>null</tt> if called on the workflow
-	 *         run's working directory.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	public RemoteDirectory getContainingDirectory() throws RemoteException;
-
-	/**
-	 * Destroy this directory entry, deleting the file or sub-directory. The
-	 * workflow run's working directory can never be manually destroyed.
-	 * 
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong when deleting the directory entry.
-	 */
-	public void destroy() throws RemoteException, IOException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
deleted file mode 100644
index e09466d..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteFile.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.io.IOException;
-import java.rmi.RemoteException;
-
-import javax.annotation.Nonnull;
-
-/**
- * Represents a file in the working directory of a workflow instance run, or in
- * some sub-directory of it.
- * 
- * @author Donal Fellows
- * @see RemoteDirectory
- */
-public interface RemoteFile extends RemoteDirectoryEntry {
-	/**
-	 * Read from the file.
-	 * 
-	 * @param offset
-	 *            Where in the file to read the bytes from.
-	 * @param length
-	 *            How much of the file to read; -1 for "to the end".
-	 * @return The literal byte contents of the given section of the file.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong reading the file.
-	 */
-	@Nonnull
-	byte[] getContents(int offset, int length) throws RemoteException,
-			IOException;
-
-	/**
-	 * Write the data to the file, totally replacing what was there before.
-	 * 
-	 * @param data
-	 *            The literal bytes that will form the new contents of the file.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong writing the contents.
-	 */
-	void setContents(@Nonnull byte[] data) throws RemoteException, IOException;
-
-	/**
-	 * Append the data to the file.
-	 * 
-	 * @param data
-	 *            The literal bytes that will be appended.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong writing the contents.
-	 */
-	void appendContents(@Nonnull byte[] data) throws RemoteException,
-			IOException;
-
-	/**
-	 * @return The length of the file, in bytes.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	long getSize() throws RemoteException;
-
-	/**
-	 * Copy from another file to this one.
-	 * 
-	 * @param sourceFile
-	 *            The other file to copy from.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws IOException
-	 *             If things go wrong during the copy.
-	 */
-	void copy(@Nonnull RemoteFile sourceFile) throws RemoteException,
-			IOException;
-
-	/**
-	 * @return The full native OS name for the file.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	String getNativeName() throws RemoteException;
-
-	/**
-	 * @return The host holding the file.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	String getNativeHost() throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
deleted file mode 100644
index 7a7510c..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteInput.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-/**
- * This represents the assignment of inputs to input ports of the workflow. Note
- * that the <tt>file</tt> and <tt>value</tt> properties are never set at the
- * same time.
- * 
- * @author Donal Fellows
- */
-public interface RemoteInput extends Remote {
-	/**
-	 * @return The file currently assigned to this input port, or <tt>null</tt>
-	 *         if no file is assigned.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	String getFile() throws RemoteException;
-
-	/**
-	 * @return The name of this input port. This may not be changed.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	String getName() throws RemoteException;
-
-	/**
-	 * @return The value currently assigned to this input port, or <tt>null</tt>
-	 *         if no value is assigned.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	String getValue() throws RemoteException;
-
-	/**
-	 * @return The delimiter currently used to split this input port's value
-	 *         into a list, or <tt>null</tt> if no delimiter is to be used
-	 *         (i.e., the value is a singleton).
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	String getDelimiter() throws RemoteException;
-
-	/**
-	 * Sets the file to use for this input. This overrides the use of the
-	 * previous file and any set value.
-	 * 
-	 * @param file
-	 *            The filename to use. Must not start with a <tt>/</tt> or
-	 *            contain any <tt>..</tt> segments. Will be interpreted relative
-	 *            to the run's working directory.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setFile(@Nonnull String file) throws RemoteException;
-
-	/**
-	 * Sets the value to use for this input. This overrides the use of the
-	 * previous value and any set file.
-	 * 
-	 * @param value
-	 *            The value to use.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setValue(@Nonnull String value) throws RemoteException;
-
-	/**
-	 * Sets the delimiter used to split this input port's value into a list.
-	 * 
-	 * @param delimiter
-	 *            The delimiter character, or <tt>null</tt> if no delimiter is
-	 *            to be used (i.e., the value is a singleton).
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setDelimiter(@Nullable String delimiter) throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
deleted file mode 100644
index 4001721..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteListener.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.annotation.Nonnull;
-
-/**
- * An event listener that is attached to a {@link RemoteSingleRun}.
- * 
- * @author Donal Fellows
- */
-public interface RemoteListener extends Remote {
-	/**
-	 * @return The name of the listener.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String getName() throws RemoteException;
-
-	/**
-	 * @return The type of the listener.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String getType() throws RemoteException;
-
-	/**
-	 * @return The configuration document for the listener.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String getConfiguration() throws RemoteException;
-
-	/**
-	 * @return The supported properties of the listener.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String[] listProperties() throws RemoteException;
-
-	/**
-	 * Get the value of a particular property, which should be listed in the
-	 * {@link #listProperties()} method.
-	 * 
-	 * @param propName
-	 *            The name of the property to read.
-	 * @return The value of the property.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public String getProperty(@Nonnull String propName) throws RemoteException;
-
-	/**
-	 * Set the value of a particular property, which should be listed in the
-	 * {@link #listProperties()} method.
-	 * 
-	 * @param propName
-	 *            The name of the property to write.
-	 * @param value
-	 *            The value to set the property to.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	public void setProperty(@Nonnull String propName, @Nonnull String value)
-			throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
deleted file mode 100644
index eec4ab5..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteRunFactory.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.UUID;
-
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-/**
- * The main RMI-enabled interface for creating runs.
- * 
- * @author Donal Fellows
- */
-public interface RemoteRunFactory extends Remote {
-	/**
-	 * Makes a workflow run that will process a particular workflow document.
-	 * 
-	 * @param workflow
-	 *            The (serialised) workflow to instantiate as a run.
-	 * @param creator
-	 *            Who is this run created for?
-	 * @param usageRecordReceiver
-	 *            Where to write any usage records. May be <tt>null</tt> to
-	 *            cause them to not be written.
-	 * @param masterID
-	 *            The UUID of the run to use, or <tt>null</tt> if the execution
-	 *            engine is to manufacture a new one for itself.
-	 * @return A remote handle for the run.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	RemoteSingleRun make(@Nonnull byte[] workflow, @Nonnull String creator,
-			@Nullable UsageRecordReceiver usageRecordReceiver,
-			@Nullable UUID masterID) throws RemoteException;
-
-	/**
-	 * Asks this factory to unregister itself from the registry and cease
-	 * operation.
-	 * 
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void shutdown() throws RemoteException;
-
-	/**
-	 * Configures the details to use when setting up the workflow run's
-	 * connnection to the interaction feed.
-	 * 
-	 * @param host
-	 *            The host where the feed is located.
-	 * @param port
-	 *            The port where the feed is located.
-	 * @param webdavPath
-	 *            The path used for pushing web pages into the feed.
-	 * @param feedPath
-	 *            The path used for reading and writing notifications on the
-	 *            feed.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setInteractionServiceDetails(@Nonnull String host,
-			@Nonnull String port, @Nonnull String webdavPath,
-			@Nonnull String feedPath) throws RemoteException;
-
-	/**
-	 * Gets a count of the number of {@linkplain RemoteSingleRun workflow runs}
-	 * that this factor knows about that are in the
-	 * {@link RemoteStatus#Operating Operating} state.
-	 * 
-	 * @return A count of "running" workflow runs.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	int countOperatingRuns() throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
deleted file mode 100644
index 35e6c09..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSecurityContext.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.net.URI;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-
-/**
- * Outline of the security context for a workflow run.
- * 
- * @author Donal Fellows
- */
-public interface RemoteSecurityContext extends Remote {
-	void setKeystore(@Nonnull byte[] keystore) throws RemoteException,
-			ImplementationException;
-
-	void setPassword(@Nonnull char[] password) throws RemoteException,
-			ImplementationException;
-
-	void setTruststore(@Nonnull byte[] truststore) throws RemoteException,
-			ImplementationException;
-
-	void setUriToAliasMap(@Nonnull Map<URI, String> uriToAliasMap)
-			throws RemoteException;
-
-	void setHelioToken(@Nonnull String helioToken) throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
deleted file mode 100644
index fa68b81..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteSingleRun.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-import java.net.URL;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-public interface RemoteSingleRun extends Remote {
-	/**
-	 * @return The name of the Baclava file to use for all inputs, or
-	 *         <tt>null</tt> if no Baclava file is set.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	public String getInputBaclavaFile() throws RemoteException;
-
-	/**
-	 * Sets the Baclava file to use for all inputs. This overrides the use of
-	 * individual inputs.
-	 * 
-	 * @param filename
-	 *            The filename to use. Must not start with a <tt>/</tt> or
-	 *            contain any <tt>..</tt> segments. Will be interpreted relative
-	 *            to the run's working directory.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	public void setInputBaclavaFile(@Nonnull String filename)
-			throws RemoteException;
-
-	/**
-	 * @return The list of input assignments.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public List<RemoteInput> getInputs() throws RemoteException;
-
-	/**
-	 * Create an input assignment.
-	 * 
-	 * @param name
-	 *            The name of the port that this will be an input for.
-	 * @return The assignment reference.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public RemoteInput makeInput(@Nonnull String name) throws RemoteException;
-
-	/**
-	 * @return The file (relative to the working directory) to write the outputs
-	 *         of the run to as a Baclava document, or <tt>null</tt> if they are
-	 *         to be written to non-Baclava files in a directory called
-	 *         <tt>out</tt>.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	public String getOutputBaclavaFile() throws RemoteException;
-
-	/**
-	 * Sets where the output of the run is to be written to. This will cause the
-	 * output to be generated as a Baclava document, rather than a collection of
-	 * individual non-Baclava files in the subdirectory of the working directory
-	 * called <tt>out</tt>.
-	 * 
-	 * @param filename
-	 *            Where to write the Baclava file (or <tt>null</tt> to cause the
-	 *            output to be written to individual files); overwrites any
-	 *            previous setting of this value.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	public void setOutputBaclavaFile(@Nullable String filename)
-			throws RemoteException;
-
-	/**
-	 * @return The current status of the run.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public RemoteStatus getStatus() throws RemoteException;
-
-	/**
-	 * Set the status of the run, which should cause it to move into the given
-	 * state. This may cause some significant changes.
-	 * 
-	 * @param s
-	 *            The state to try to change to.
-	 * @throws IllegalStateTransitionException
-	 *             If the requested state change is impossible. (Note that it is
-	 *             always legal to set the status to the current status.)
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws ImplementationException
-	 *             If something goes horribly wrong on the back end.
-	 * @throws StillWorkingOnItException
-	 *             If the startup time of the workflow implementation exceeds a
-	 *             built-in threshold.
-	 */
-	public void setStatus(@Nonnull RemoteStatus s)
-			throws IllegalStateTransitionException, RemoteException,
-			ImplementationException, StillWorkingOnItException;
-
-	/**
-	 * @return When this workflow run was found to have finished, or
-	 *         <tt>null</tt> if it has never finished (either still running or
-	 *         never started).
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	public Date getFinishTimestamp() throws RemoteException;
-
-	/**
-	 * @return When this workflow run was started, or <tt>null</tt> if it has
-	 *         never been started.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nullable
-	public Date getStartTimestamp() throws RemoteException;
-
-	/**
-	 * @return Handle to the main working directory of the run.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public RemoteDirectory getWorkingDirectory() throws RemoteException;
-
-	/**
-	 * @return The list of listener instances attached to the run.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public List<RemoteListener> getListeners() throws RemoteException;
-
-	/**
-	 * Add a listener to the run.
-	 * 
-	 * @param listener
-	 *            The listener to add.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws ImplementationException
-	 *             If something goes wrong when adding the listener.
-	 */
-	public void addListener(@Nonnull RemoteListener listener)
-			throws RemoteException, ImplementationException;
-
-	/**
-	 * @return The security context structure for this run.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws ImplementationException
-	 *             If something goes wrong when getting the context.
-	 */
-	@Nonnull
-	public RemoteSecurityContext getSecurityContext() throws RemoteException,
-			ImplementationException;
-
-	/**
-	 * Kill off this run, removing all resources which it consumes.
-	 * 
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 * @throws ImplementationException
-	 *             If something goes horribly wrong when destroying the run.
-	 */
-	public void destroy() throws RemoteException, ImplementationException;
-
-	/**
-	 * Get the types of listener supported by this run.
-	 * 
-	 * @return A list of listener type names.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public List<String> getListenerTypes() throws RemoteException;
-
-	/**
-	 * Create a listener that can be attached to this run.
-	 * 
-	 * @param type
-	 *            The type name of the listener to create; it must be one of the
-	 *            names returned by the {@link #getListenerTypes()} operation.
-	 * @param configuration
-	 *            The configuration document for this listener. The nature of
-	 *            the contents of this are determined by the type.
-	 * @return A handle for the listener.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	@Nonnull
-	public RemoteListener makeListener(@Nonnull String type,
-			@Nonnull String configuration) throws RemoteException;
-
-	/**
-	 * Configures the details to use when setting up the workflow run's
-	 * connnection to the interaction feed.
-	 * 
-	 * @param interactionFeed
-	 *            The location of the interaction feed. If <tt>null</tt>,
-	 *            defaults from the factory will be used instead.
-	 * @param webdavPath
-	 *            The location used for pushing web pages to support the feed.
-	 *            If <tt>null</tt>, a default from the factory will be used
-	 *            instead.
-	 * @param publishUrlBase
-	 *            Where to <i>actually</i> publish to, if this needs to be
-	 *            different from the location presented in the published HTML
-	 *            and Feed entries. Necessary in complex network scenarios.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setInteractionServiceDetails(@Nonnull URL interactionFeed,
-			@Nonnull URL webdavPath, @Nullable URL publishUrlBase) throws RemoteException;
-
-	/**
-	 * A do-nothing method, used to check the general reachability of the
-	 * workflow run.
-	 * 
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void ping() throws RemoteException;
-
-	/**
-	 * Sets whether we should generate provenance information from a run.
-	 * 
-	 * @param generateProvenance
-	 *            Boolean flag, true for do the generation. Must be set before
-	 *            starting the run for this to have an effect.
-	 * @throws RemoteException
-	 *             If anything goes wrong with the communication.
-	 */
-	void setGenerateProvenance(boolean generateProvenance)
-			throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
deleted file mode 100644
index db039f0..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/RemoteStatus.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-/**
- * States of a workflow run. They are {@link RemoteStatus#Initialized
- * Initialized}, {@link RemoteStatus#Operating Operating},
- * {@link RemoteStatus#Stopped Stopped}, and {@link RemoteStatus#Finished
- * Finished}. Conceptually, there is also a <tt>Destroyed</tt> state, but the
- * workflow run does not exist (and hence can't have its state queried or set)
- * in that case.
- * 
- * @author Donal Fellows
- */
-public enum RemoteStatus {
-	/**
-	 * The workflow run has been created, but is not yet running. The run will
-	 * need to be manually moved to {@link #Operating} when ready.
-	 */
-	Initialized,
-	/**
-	 * The workflow run is going, reading input, generating output, etc. Will
-	 * eventually either move automatically to {@link #Finished} or can be moved
-	 * manually to {@link #Stopped} (where supported).
-	 */
-	Operating,
-	/**
-	 * The workflow run is paused, and will need to be moved back to
-	 * {@link #Operating} manually.
-	 */
-	Stopped,
-	/**
-	 * The workflow run has ceased; data files will continue to exist until the
-	 * run is destroyed (which may be manual or automatic).
-	 */
-	Finished
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
deleted file mode 100644
index 4643d5c..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/StillWorkingOnItException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.remote;
-
-/**
- * Exception that indicates that the implementation is still working on
- * processing the operation. Note that though this is an exception, it is <i>not
- * a failure</i>.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class StillWorkingOnItException extends Exception {
-	public StillWorkingOnItException(String string) {
-		super(string);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java b/server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
deleted file mode 100644
index 9880a3b..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/remote/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Interfaces exported by worker classes to the server.
- */
-package org.taverna.server.localworker.remote;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java b/server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
deleted file mode 100644
index 89c29ae..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/server/UsageRecordReceiver.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.server;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-/**
- * Interface exported by (part of) the webapp to allow processes it creates to
- * push in usage records.
- * 
- * @author Donal Fellows
- */
-public interface UsageRecordReceiver extends Remote {
-	/**
-	 * Called to push in a usage record. Note that it is assumed that the usage
-	 * record already contains all the information required to locate and
-	 * process the job; there is no separate handle.
-	 * 
-	 * @param usageRecord
-	 *            The serialised XML of the usage record.
-	 * @throws RemoteException
-	 *             if anything goes wrong.
-	 */
-	void acceptUsageRecord(String usageRecord) throws RemoteException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
----------------------------------------------------------------------
diff --git a/server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java b/server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
deleted file mode 100644
index cdd592b..0000000
--- a/server-runinterface/src/main/java/org/taverna/server/localworker/server/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Interfaces exported by the server to worker classes.
- */
-package org.taverna.server.localworker.server;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-unix-forker/pom.xml
----------------------------------------------------------------------
diff --git a/server-unix-forker/pom.xml b/server-unix-forker/pom.xml
deleted file mode 100644
index a2beeb4..0000000
--- a/server-unix-forker/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-unix-forker</artifactId>
-	<name>Apache Taverna Server Impersonation Module (Unix)</name>
-	<description>Manages the starting of the worker processes as different users. Unix-specific.</description>
-
-	<properties>
-		<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
-		<forkerMainClass>org.taverna.server.unixforker.Forker</forkerMainClass>
-	</properties>
-
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<configuration>
-					<descriptorRefs>
-						<descriptorRef>jar-with-dependencies</descriptorRef>
-					</descriptorRefs>
-					<archive>
-						<manifest>
-							<mainClass>${forkerMainClass}</mainClass>
-						</manifest>
-					</archive>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-assembly</id>
-						<phase>package</phase>
-						<goals>
-							<goal>single</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
----------------------------------------------------------------------
diff --git a/server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java b/server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
deleted file mode 100644
index f9dc632..0000000
--- a/server-unix-forker/src/main/java/org/taverna/server/unixforker/Forker.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.unixforker;
-
-import static java.lang.System.err;
-import static java.lang.System.getProperty;
-import static java.lang.System.in;
-import static java.lang.System.out;
-import static java.util.Arrays.asList;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
-/**
- * A simple class that forks off processes when asked to over its standard
- * input. The one complication is that it forks them off as other users, through
- * the use of the <tt>sudo</tt> utility. It is Unix-specific.
- * 
- * @author Donal Fellows
- */
-public class Forker extends Thread {
-	private static String password;
-	private static BufferedReader br;
-
-	/**
-	 * Helper to make reading a password from a file clearer. The password must
-	 * be the first line of the file.
-	 * 
-	 * @param passwordFile
-	 *            The file to load from.
-	 * @throws IOException
-	 *             If anything goes wrong.
-	 */
-	private static void loadPassword(@Nonnull File passwordFile)
-			throws IOException {
-		try {
-			err.println("attempting to load password from " + passwordFile);
-			try (FileReader fr = new FileReader(passwordFile)) {
-				password = new BufferedReader(fr).readLine();
-			}
-		} catch (IOException e) {
-			err.println("failed to read password from file " + passwordFile
-					+ "described in password.file property");
-			throw e;
-		}
-	}
-
-	/**
-	 * Initialization code, which runs before the main loop starts processing.
-	 * 
-	 * @param args
-	 *            The arguments to the program.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	public static void init(String[] args) throws Exception {
-		if (args.length < 1)
-			throw new IllegalArgumentException(
-					"wrong # args: must be \"program ?argument ...?\"");
-		if (getProperty("password.file") != null)
-			loadPassword(new File(getProperty("password.file")));
-		if (password == null)
-			err.println("no password.file property or empty file; "
-					+ "assuming password-less sudo is configured");
-		else
-			err.println("password is of length " + password.length());
-		br = new BufferedReader(new InputStreamReader(in));
-	}
-
-	/**
-	 * The body of the main loop of this program.
-	 * 
-	 * @param args
-	 *            The arguments to use when running the other program.
-	 * @return Whether to repeat the loop.
-	 * @throws Exception
-	 *             If anything goes wrong. Note that the loop is repeated if an
-	 *             exception occurs in it.
-	 */
-	public static boolean mainLoopBody(String[] args) throws Exception {
-		String line = br.readLine();
-		if (line == null)
-			return false;
-		List<String> vals = asList(line.split("[ \t]+"));
-		if (vals.size() != 2) {
-			out.println("wrong # values: must be \"username UUID\"");
-			return true;
-		}
-		ProcessBuilder pb = new ProcessBuilder();
-		pb.command()
-				.addAll(asList("sudo", "-u", vals.get(0), "-S", "-H", "--"));
-		pb.command().addAll(asList(args));
-		pb.command().add(vals.get(1));
-		Forker f = new Forker(pb);
-		f.setDaemon(true);
-		f.start();
-		return true;
-	}
-
-	/**
-	 * The main code for this class, which turns this into an executable
-	 * program. Runs the initialisation and then the main loop, in both cases
-	 * with appropriate error handling.
-	 * 
-	 * @param args
-	 *            Arguments to this program.
-	 */
-	public static void main(String... args) {
-		try {
-			init(args);
-			while (true) {
-				try {
-					if (!mainLoopBody(args))
-						break;
-				} catch (Exception e) {
-					e.printStackTrace(err);
-					out.println(e.getClass().getName() + ": " + e.getMessage());
-				}
-			}
-			System.exit(0);
-		} catch (Exception e) {
-			e.printStackTrace(err);
-			System.exit(1);
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	public Forker(ProcessBuilder pb) throws IOException {
-		out.println("Starting subprocess: " + pb.command());
-		final Process p = pb.start();
-		abstract class ProcessAttachedDaemon extends Thread {
-			public ProcessAttachedDaemon() {
-				setDaemon(true);
-				start();
-			}
-
-			abstract void act() throws Exception;
-
-			@Override
-			public final void run() {
-				try {
-					act();
-					p.waitFor();
-				} catch (InterruptedException e) {
-					// Just drop
-				} catch (Exception e) {
-					p.destroy();
-					e.printStackTrace(err);
-				}
-			}
-		}
-		new ProcessAttachedDaemon() {
-			@Override
-			void act() throws Exception {
-				copyFromSudo("Subprocess(out):", p.getInputStream());
-			}
-		};
-		new ProcessAttachedDaemon() {
-			@Override
-			void act() throws Exception {
-				copyFromSudo("Subprocess(err):", p.getErrorStream());
-			}
-		};
-		new ProcessAttachedDaemon() {
-			@Override
-			void act() throws Exception {
-				interactWithSudo(p.getOutputStream());
-			}
-		};
-	}
-
-	protected void interactWithSudo(OutputStream os) throws Exception {
-		if (password != null) {
-			OutputStreamWriter osw = new OutputStreamWriter(os);
-			osw.write(password + "\n");
-			osw.flush();
-		}
-		os.close();
-	}
-
-	protected void copyFromSudo(String header, InputStream sudoStream)
-			throws Exception {
-		int b = '\n';
-		while (true) {
-			if (b == '\n')
-				out.print(header);
-			b = sudoStream.read();
-			if (b == -1)
-				break;
-			out.write(b);
-			out.flush();
-		}
-		sudoStream.close();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/.gitignore
----------------------------------------------------------------------
diff --git a/server-usagerecord/.gitignore b/server-usagerecord/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/server-usagerecord/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/pom.xml
----------------------------------------------------------------------
diff --git a/server-usagerecord/pom.xml b/server-usagerecord/pom.xml
deleted file mode 100644
index 47ab732..0000000
--- a/server-usagerecord/pom.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-usagerecord</artifactId>
-	<name>Apache Taverna Server Usage Record Support</name>
-	<description>Basic Java bindings for the OGF Usage Record Format, version 1.0, plus a simple wrapper to make working with it easier.</description>
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.codehaus.mojo</groupId>
-				<artifactId>jaxb2-maven-plugin</artifactId>
-				<version>1.3.1</version>
-				<executions>
-					<execution>
-						<id>xsd2java</id>
-						<goals>
-							<goal>xjc</goal>
-						</goals>
-						<configuration>
-							<outputDirectory>${project.build.directory}/generated-sources/xjc</outputDirectory>
-							<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
-
-		</plugins>
-		<pluginManagement>
-			<plugins>
-				<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
-				<plugin>
-					<groupId>org.eclipse.m2e</groupId>
-					<artifactId>lifecycle-mapping</artifactId>
-					<version>1.0.0</version>
-					<configuration>
-						<lifecycleMappingMetadata>
-							<pluginExecutions>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>org.codehaus.mojo</groupId>
-										<artifactId>jaxb2-maven-plugin</artifactId>
-										<versionRange>[1.3.1,)</versionRange>
-										<goals>
-											<goal>xjc</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute />
-									</action>
-								</pluginExecution>
-							</pluginExecutions>
-						</lifecycleMappingMetadata>
-					</configuration>
-				</plugin>
-			</plugins>
-		</pluginManagement>
-	</build>
-</project>


[20/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
new file mode 100644
index 0000000..48969fa
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/DirectoryREST.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.seeOther;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+import static org.taverna.server.master.api.ContentTypes.DIRECTORY_VARIANTS;
+import static org.taverna.server.master.api.ContentTypes.INITIAL_FILE_VARIANTS;
+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.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+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.ws.rs.core.Variant;
+import javax.xml.ws.Holder;
+
+import org.apache.commons.logging.Log;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.DirectoryBean;
+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.DirectoryEntry;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.DirectoryContents;
+import org.taverna.server.master.rest.FileSegment;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry.MakeDirectory;
+import org.taverna.server.master.rest.TavernaServerDirectoryREST;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful access to the filesystem.
+ * 
+ * @author Donal Fellows
+ */
+class DirectoryREST implements TavernaServerDirectoryREST, DirectoryBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private TavernaServerSupport support;
+	private TavernaRun run;
+	private FilenameUtils fileUtils;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Override
+	public DirectoryREST connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response destroyDirectoryEntry(List<PathSegment> path)
+			throws NoUpdateException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		support.permitUpdate(run);
+		fileUtils.getDirEntry(run, path).destroy();
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public DirectoryContents getDescription(UriInfo ui)
+			throws FilesystemAccessException {
+		return new DirectoryContents(ui, run.getWorkingDirectory()
+				.getContents());
+	}
+
+	@Override
+	@CallCounted
+	public Response options(List<PathSegment> path) {
+		return opt("PUT", "POST", "DELETE");
+	}
+
+	/*
+	 * // Nasty! This can have several different responses...
+	 * 
+	 * @Override @CallCounted private Response
+	 * getDirectoryOrFileContents(List<PathSegment> path, UriInfo ui, Request
+	 * req) throws FilesystemAccessException, NoDirectoryEntryException {
+	 * 
+	 * DirectoryEntry de = fileUtils.getDirEntry(run, path);
+	 * 
+	 * // How did the user want the result?
+	 * 
+	 * List<Variant> variants = getVariants(de); Variant v =
+	 * req.selectVariant(variants); if (v == null) return
+	 * notAcceptable(variants).type(TEXT_PLAIN)
+	 * .entity("Do not know what type of response to produce.") .build();
+	 * 
+	 * // Produce the content to deliver up
+	 * 
+	 * Object result; if
+	 * (v.getMediaType().equals(APPLICATION_OCTET_STREAM_TYPE))
+	 * 
+	 * // Only for files...
+	 * 
+	 * result = de; else if (v.getMediaType().equals(APPLICATION_ZIP_TYPE))
+	 * 
+	 * // Only for directories...
+	 * 
+	 * result = ((Directory) de).getContentsAsZip(); else
+	 * 
+	 * // Only for directories... // XML or JSON; let CXF pick what to do
+	 * 
+	 * result = new DirectoryContents(ui, ((Directory) de).getContents());
+	 * return ok(result).type(v.getMediaType()).build();
+	 * 
+	 * }
+	 */
+
+	private boolean matchType(MediaType a, MediaType b) {
+		if (log.isDebugEnabled())
+			log.debug("comparing " + a.getType() + "/" + a.getSubtype()
+					+ " and " + b.getType() + "/" + b.getSubtype());
+		return (a.isWildcardType() || b.isWildcardType() || a.getType().equals(
+				b.getType()))
+				&& (a.isWildcardSubtype() || b.isWildcardSubtype() || a
+						.getSubtype().equals(b.getSubtype()));
+	}
+
+	/**
+	 * What are we willing to serve up a directory or file as?
+	 * 
+	 * @param de
+	 *            The reference to the object to serve.
+	 * @return The variants we can serve it as.
+	 * @throws FilesystemAccessException
+	 *             If we fail to read data necessary to detection of its media
+	 *             type.
+	 */
+	private List<Variant> getVariants(DirectoryEntry de)
+			throws FilesystemAccessException {
+		if (de instanceof Directory)
+			return DIRECTORY_VARIANTS;
+		else if (!(de instanceof File))
+			throw new FilesystemAccessException("not a directory or file!");
+		File f = (File) de;
+		List<Variant> variants = new ArrayList<>(INITIAL_FILE_VARIANTS);
+		String contentType = support.getEstimatedContentType(f);
+		if (!contentType.equals(APPLICATION_OCTET_STREAM)) {
+			String[] ct = contentType.split("/");
+			variants.add(0,
+					new Variant(new MediaType(ct[0], ct[1]), (String) null, null));
+		}
+		return variants;
+	}
+
+	/** How did the user want the result? */
+	private MediaType pickType(HttpHeaders headers, DirectoryEntry de)
+			throws FilesystemAccessException, NegotiationFailedException {
+		List<Variant> variants = getVariants(de);
+		// Manual content negotiation!!! Ugh!
+		for (MediaType mt : headers.getAcceptableMediaTypes())
+			for (Variant v : variants)
+				if (matchType(mt, v.getMediaType()))
+					return v.getMediaType();
+		throw new NegotiationFailedException(
+				"Do not know what type of response to produce.", variants);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response getDirectoryOrFileContents(List<PathSegment> path,
+			UriInfo ui, HttpHeaders headers) throws FilesystemAccessException,
+			NoDirectoryEntryException, NegotiationFailedException {
+		DirectoryEntry de = fileUtils.getDirEntry(run, path);
+
+		// How did the user want the result?
+		MediaType wanted = pickType(headers, de);
+
+		log.info("producing content of type " + wanted);
+		// Produce the content to deliver up
+		Object result;
+		if (de instanceof File) {
+			// Only for files...
+			result = de;
+			List<String> range = headers.getRequestHeader("Range");
+			if (range != null && range.size() == 1)
+				return new FileSegment((File) de, range.get(0))
+						.toResponse(wanted);
+		} else {
+			// Only for directories...
+			Directory d = (Directory) de;
+			if (wanted.getType().equals(APPLICATION_ZIP_TYPE.getType())
+					&& wanted.getSubtype().equals(
+							APPLICATION_ZIP_TYPE.getSubtype()))
+				result = d.getContentsAsZip();
+			else
+				// XML or JSON; let CXF pick what to do
+				result = new DirectoryContents(ui, d.getContents());
+		}
+		return ok(result).type(wanted).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response makeDirectoryOrUpdateFile(List<PathSegment> parent,
+			MakeOrUpdateDirEntry op, UriInfo ui) throws NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException {
+		support.permitUpdate(run);
+		DirectoryEntry container = fileUtils.getDirEntry(run, parent);
+		if (!(container instanceof Directory))
+			throw new FilesystemAccessException("You may not "
+					+ ((op instanceof MakeDirectory) ? "make a subdirectory of"
+							: "place a file in") + " a file.");
+		if (op.name == null || op.name.length() == 0)
+			throw new FilesystemAccessException("missing name attribute");
+		Directory d = (Directory) container;
+		UriBuilder ub = secure(ui).path("{name}");
+
+		// Make a directory in the context directory
+
+		if (op instanceof MakeDirectory) {
+			Directory target = d.makeSubdirectory(support.getPrincipal(),
+					op.name);
+			return created(ub.build(target.getName())).build();
+		}
+
+		// Make or set the contents of a file
+
+		File f = null;
+		for (DirectoryEntry e : d.getContents()) {
+			if (e.getName().equals(op.name)) {
+				if (e instanceof Directory)
+					throw new FilesystemAccessException(
+							"You may not overwrite a directory with a file.");
+				f = (File) e;
+				break;
+			}
+		}
+		if (f == null) {
+			f = d.makeEmptyFile(support.getPrincipal(), op.name);
+			f.setContents(op.contents);
+			return created(ub.build(f.getName())).build();
+		}
+		f.setContents(op.contents);
+		return seeOther(ub.build(f.getName())).build();
+	}
+
+	private File getFileForWrite(List<PathSegment> filePath,
+			Holder<Boolean> isNew) throws FilesystemAccessException,
+			NoDirectoryEntryException, NoUpdateException {
+		support.permitUpdate(run);
+		if (filePath == null || filePath.size() == 0)
+			throw new FilesystemAccessException(
+					"Cannot create a file that is not in a directory.");
+
+		List<PathSegment> dirPath = new ArrayList<>(filePath);
+		String name = dirPath.remove(dirPath.size() - 1).getPath();
+		DirectoryEntry de = fileUtils.getDirEntry(run, dirPath);
+		if (!(de instanceof Directory)) {
+			throw new FilesystemAccessException(
+					"Cannot create a file that is not in a directory.");
+		}
+		Directory d = (Directory) de;
+
+		File f = null;
+		isNew.value = false;
+		for (DirectoryEntry e : d.getContents())
+			if (e.getName().equals(name)) {
+				if (e instanceof File) {
+					f = (File) e;
+					break;
+				}
+				throw new FilesystemAccessException(
+						"Cannot create a file that is not in a directory.");
+			}
+
+		if (f == null) {
+			f = d.makeEmptyFile(support.getPrincipal(), name);
+			isNew.value = true;
+		} else
+			f.setContents(new byte[0]);
+		return f;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response setFileContents(List<PathSegment> filePath,
+			InputStream contents, UriInfo ui) throws NoDirectoryEntryException,
+			NoUpdateException, FilesystemAccessException {
+		Holder<Boolean> isNew = new Holder<>(true);
+		support.copyStreamToFile(contents, getFileForWrite(filePath, isNew));
+
+		if (isNew.value)
+			return created(ui.getAbsolutePath()).build();
+		else
+			return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response setFileContentsFromURL(List<PathSegment> filePath,
+			List<URI> referenceList, UriInfo ui)
+			throws NoDirectoryEntryException, NoUpdateException,
+			FilesystemAccessException {
+		support.permitUpdate(run);
+		if (referenceList.isEmpty() || referenceList.size() > 1)
+			return status(422).entity("URI list must have single URI in it")
+					.build();
+		URI uri = referenceList.get(0);
+		try {
+			uri.toURL();
+		} catch (MalformedURLException e) {
+			return status(422).entity("URI list must have value URL in it")
+					.build();
+		}
+		Holder<Boolean> isNew = new Holder<>(true);
+		File f = getFileForWrite(filePath, isNew);
+
+		try {
+			support.copyDataToFile(uri, f);
+		} catch (MalformedURLException ex) {
+			// Should not happen; called uri.toURL() successfully above
+			throw new NoUpdateException("failed to parse URI", ex);
+		} catch (IOException ex) {
+			throw new FilesystemAccessException(
+					"failed to transfer data from URI", ex);
+		}
+
+		if (isNew.value)
+			return created(ui.getAbsolutePath()).build();
+		else
+			return noContent().build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
new file mode 100644
index 0000000..3893b3d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/FileConcatenation.java
@@ -0,0 +1,68 @@
+package org.taverna.server.master;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * Simple concatenation of files.
+ * 
+ * @author Donal Fellows
+ */
+public class FileConcatenation implements Iterable<File> {
+	private List<File> files = new ArrayList<>();
+
+	public void add(File f) {
+		files.add(f);
+	}
+
+	public boolean isEmpty() {
+		return files.isEmpty();
+	}
+
+	/**
+	 * @return The total length of the files, or -1 if this cannot be
+	 *         determined.
+	 */
+	public long size() {
+		long size = 0;
+		for (File f : files)
+			try {
+				size += f.getSize();
+			} catch (FilesystemAccessException e) {
+				// Ignore; shouldn't happen but can't guarantee
+			}
+		return (size == 0 && !files.isEmpty() ? -1 : size);
+	}
+
+	/**
+	 * Get the concatenated files.
+	 * 
+	 * @param encoding
+	 *            The encoding to use.
+	 * @return The concatenated files.
+	 * @throws UnsupportedEncodingException
+	 *             If the encoding doesn't exist.
+	 */
+	public String get(String encoding) throws UnsupportedEncodingException {
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		for (File f : files)
+			try {
+				baos.write(f.getContents(0, -1));
+			} catch (FilesystemAccessException | IOException e) {
+				continue;
+			}
+		return baos.toString(encoding);
+	}
+
+	@Override
+	public Iterator<File> iterator() {
+		return files.iterator();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
new file mode 100644
index 0000000..0f48207
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/InputREST.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.Date;
+
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.model.URITemplate;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.InputBean;
+import org.taverna.server.master.common.DirEntryReference;
+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.NoDirectoryEntryException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+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.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.AbstractContents;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc.Reference;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.taverna.server.port_description.InputDescription;
+
+/**
+ * RESTful interface to the input descriptor of a single workflow run.
+ * 
+ * @author Donal Fellows
+ */
+class InputREST implements TavernaServerInputREST, InputBean {
+	private UriInfo ui;
+	private TavernaServerSupport support;
+	private TavernaRun run;
+	private ContentsDescriptorBuilder cdBuilder;
+	private FilenameUtils fileUtils;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
+		this.cdBuilder = cdBuilder;
+	}
+
+	@Override
+	@Required
+	public void setFileUtils(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Override
+	public InputREST connect(TavernaRun run, UriInfo ui) {
+		this.run = run;
+		this.ui = ui;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InputsDescriptor get() {
+		return new InputsDescriptor(ui, run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InputDescription getExpected() {
+		return cdBuilder.makeInputDescriptor(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getBaclavaFile() {
+		String i = run.getInputBaclavaFile();
+		return i == null ? "" : i;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InDesc getInput(String name, UriInfo ui) throws BadInputPortNameException {
+		Input i = support.getInput(run, name);
+		if (i == null)
+			throw new BadInputPortNameException("unknown input port name");
+		return new InDesc(i, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String setBaclavaFile(String filename) throws NoUpdateException,
+			BadStateChangeException, FilesystemAccessException {
+		support.permitUpdate(run);
+		run.setInputBaclavaFile(filename);
+		String i = run.getInputBaclavaFile();
+		return i == null ? "" : i;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public InDesc setInput(String name, InDesc inputDescriptor, UriInfo ui)
+			throws NoUpdateException, BadStateChangeException,
+			FilesystemAccessException, BadInputPortNameException,
+			BadPropertyValueException {
+		inputDescriptor.descriptorRef = null;
+		AbstractContents ac = inputDescriptor.assignment;
+		if (name == null || name.isEmpty())
+			throw new BadInputPortNameException("bad input name");
+		if (ac == null)
+			throw new BadPropertyValueException("no content!");
+		if (inputDescriptor.delimiter != null
+				&& inputDescriptor.delimiter.isEmpty())
+			inputDescriptor.delimiter = null;
+		if (ac instanceof InDesc.Reference)
+			return setRemoteInput(name, (InDesc.Reference) ac,
+					inputDescriptor.delimiter, ui);
+		if (!(ac instanceof InDesc.File || ac instanceof InDesc.Value))
+			throw new BadPropertyValueException("unknown content type");
+		support.permitUpdate(run);
+		Input i = support.getInput(run, name);
+		if (i == null)
+			i = run.makeInput(name);
+		if (ac instanceof InDesc.File)
+			i.setFile(ac.contents);
+		else
+			i.setValue(ac.contents);
+		i.setDelimiter(inputDescriptor.delimiter);
+		return new InDesc(i, ui);
+	}
+
+	private InDesc setRemoteInput(String name, Reference ref, String delimiter,
+			UriInfo ui) throws BadStateChangeException,
+			BadPropertyValueException, FilesystemAccessException {
+		URITemplate tmpl = new URITemplate(ui.getBaseUri()
+				+ "/runs/{runName}/wd/{path:.+}");
+		MultivaluedMap<String, String> mvm = new MetadataMap<>();
+		if (!tmpl.match(ref.contents, mvm)) {
+			throw new BadPropertyValueException(
+					"URI in reference does not refer to local disk resource");
+		}
+		try {
+			File from = fileUtils.getFile(
+					support.getRun(mvm.get("runName").get(0)),
+					SyntheticDirectoryEntry.make(mvm.get("path").get(0)));
+			File to = run.getWorkingDirectory().makeEmptyFile(
+					support.getPrincipal(), randomUUID().toString());
+
+			to.copy(from);
+
+			Input i = support.getInput(run, name);
+			if (i == null)
+				i = run.makeInput(name);
+			i.setFile(to.getFullName());
+			i.setDelimiter(delimiter);
+			return new InDesc(i, ui);
+		} catch (UnknownRunException e) {
+			throw new BadStateChangeException("may not copy from that run", e);
+		} catch (NoDirectoryEntryException e) {
+			throw new BadStateChangeException("source does not exist", e);
+		}
+	}
+
+	@Override
+	@CallCounted
+	public Response options() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response expectedOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response baclavaOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response inputOptions(@PathParam("name") String name) {
+		return opt("PUT");
+	}
+}
+
+/**
+ * A way to create synthetic directory entries, used during deletion.
+ * 
+ * @author Donal Fellows
+ */
+class SyntheticDirectoryEntry implements DirectoryEntry {
+	public static DirEntryReference make(String path) {
+		return DirEntryReference.newInstance(new SyntheticDirectoryEntry(path));
+	}
+
+	private SyntheticDirectoryEntry(String p) {
+		this.p = p;
+		this.d = new Date();
+	}
+
+	private String p;
+	private Date d;
+
+	@Override
+	public String getName() {
+		return null;
+	}
+
+	@Override
+	public String getFullName() {
+		return p;
+	}
+
+	@Override
+	public void destroy() {
+	}
+
+	@Override
+	public int compareTo(DirectoryEntry o) {
+		return p.compareTo(o.getFullName());
+	}
+
+	@Override
+	public Date getModificationDate() {
+		return d;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
new file mode 100644
index 0000000..b686491
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/InteractionFeed.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static org.taverna.server.master.common.Roles.SELF;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.taverna.server.master.api.FeedBean;
+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.interaction.InteractionFeedSupport;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.InteractionFeedREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * How to connect an interaction feed to the webapp.
+ * 
+ * @author Donal Fellows
+ */
+public class InteractionFeed implements InteractionFeedREST, FeedBean {
+	private InteractionFeedSupport interactionFeed;
+	private TavernaRun run;
+
+	@Override
+	public void setInteractionFeedSupport(InteractionFeedSupport feed) {
+		this.interactionFeed = feed;
+	}
+
+	InteractionFeed connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Feed getFeed() throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		return interactionFeed.getRunFeed(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Response addEntry(Entry entry) throws MalformedURLException,
+			FilesystemAccessException, NoDirectoryEntryException,
+			NoUpdateException {
+		Entry realEntry = interactionFeed.addRunFeedEntry(run, entry);
+		URI location;
+		try {
+			location = realEntry.getSelfLink().getHref().toURI();
+		} catch (URISyntaxException e) {
+			throw new RuntimeException("failed to make URI from link?!", e);
+		}
+		return Response.created(location).entity(realEntry)
+				.type("application/atom+xml;type=entry").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public Entry getEntry(String id) throws FilesystemAccessException,
+			NoDirectoryEntryException {
+		return interactionFeed.getRunFeedEntry(run, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public String deleteEntry(String id) throws FilesystemAccessException,
+			NoDirectoryEntryException, NoUpdateException {
+		interactionFeed.removeRunFeedEntry(run, id);
+		return "entry successfully deleted";
+	}
+
+	@Override
+	@CallCounted
+	public Response feedOptions() {
+		return opt("POST");
+	}
+
+	@Override
+	@CallCounted
+	public Response entryOptions(String id) {
+		return opt("DELETE");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
new file mode 100644
index 0000000..3e983a9
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenerPropertyREST.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.api.ListenerPropertyBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single property of a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+class ListenerPropertyREST implements TavernaServerListenersREST.Property,
+		ListenerPropertyBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private TavernaServerSupport support;
+	private Listener listen;
+	private String propertyName;
+	private TavernaRun run;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public ListenerPropertyREST connect(Listener listen, TavernaRun run,
+			String propertyName) {
+		this.listen = listen;
+		this.propertyName = propertyName;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getValue() {
+		try {
+			return listen.getProperty(propertyName);
+		} catch (NoListenerException e) {
+			log.error("unexpected exception; property \"" + propertyName
+					+ "\" should exist", e);
+			return null;
+		}
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String setValue(String value) throws NoUpdateException,
+			NoListenerException {
+		support.permitUpdate(run);
+		listen.setProperty(propertyName, value);
+		return listen.getProperty(propertyName);
+	}
+
+	@Override
+	@CallCounted
+	public Response options() {
+		return opt("PUT");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
new file mode 100644
index 0000000..4b7d7f3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/ListenersREST.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.ListenersBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.ListenerDefinition;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single workflow run's event listeners.
+ * 
+ * @author Donal Fellows
+ */
+abstract class ListenersREST implements TavernaServerListenersREST,
+		ListenersBean {
+	private TavernaRun run;
+	private TavernaServerSupport support;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public ListenersREST connect(TavernaRun run) {
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addListener(ListenerDefinition typeAndConfiguration,
+			UriInfo ui) throws NoUpdateException, NoListenerException {
+		String name = support.makeListener(run, typeAndConfiguration.type,
+				typeAndConfiguration.configuration).getName();
+		return created(secure(ui).path("{listenerName}").build(name)).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenerREST getListener(String name)
+			throws NoListenerException {
+		Listener l = support.getListener(run, name);
+		if (l == null)
+			throw new NoListenerException();
+		return makeListenerInterface().connect(l, run);
+	}
+
+	@Nonnull
+	protected abstract SingleListenerREST makeListenerInterface();
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Listeners getDescription(UriInfo ui) {
+		List<ListenerDescription> result = new ArrayList<>();
+		UriBuilder ub = secure(ui).path("{name}");
+		for (Listener l : run.getListeners())
+			result.add(new ListenerDescription(l,
+					fromUri(ub.build(l.getName()))));
+		return new Listeners(result, ub);
+	}
+
+	@Override
+	@CallCounted
+	public Response listenersOptions() {
+		return opt();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
new file mode 100644
index 0000000..9d4a651
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/ManagementState.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import javax.annotation.PostConstruct;
+import javax.jdo.Query;
+import javax.jdo.annotations.PersistenceAware;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.utils.JDOSupport;
+
+/** The persistent, manageable state of the Taverna Server web application. */
+@PersistenceAware
+class ManagementState extends JDOSupport<WebappState> implements
+		ManagementModel {
+	public ManagementState() {
+		super(WebappState.class);
+	}
+
+	/** Whether we should log all workflows sent to us. */
+	private boolean logIncomingWorkflows = false;
+
+	/** Whether we allow the creation of new workflow runs. */
+	private boolean allowNewWorkflowRuns = true;
+
+	/**
+	 * Whether outgoing exceptions should be logged before being converted to
+	 * responses.
+	 */
+	private boolean logOutgoingExceptions = false;
+
+	/**
+	 * The file that all usage records should be appended to, or <tt>null</tt>
+	 * if they should be just dropped.
+	 */
+	private String usageRecordLogFile = null;
+
+	@Override
+	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+		this.logIncomingWorkflows = logIncomingWorkflows;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getLogIncomingWorkflows() {
+		self.load();
+		return logIncomingWorkflows;
+	}
+
+	@Override
+	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getAllowNewWorkflowRuns() {
+		self.load();
+		return allowNewWorkflowRuns;
+	}
+
+	@Override
+	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+		this.logOutgoingExceptions = logOutgoingExceptions;
+		if (loadedState)
+			self.store();
+	}
+
+	@Override
+	public boolean getLogOutgoingExceptions() {
+		self.load();
+		return logOutgoingExceptions || true;
+	}
+
+	@Override
+	public String getUsageRecordLogFile() {
+		self.load();
+		return usageRecordLogFile;
+	}
+
+	@Override
+	public void setUsageRecordLogFile(String usageRecordLogFile) {
+		this.usageRecordLogFile = usageRecordLogFile;
+		if (loadedState)
+			self.store();
+	}
+
+	private static final int KEY = 42; // whatever
+
+	private WebappState get() {
+		Query q = query("id == " + KEY);
+		q.setUnique(true);
+		return (WebappState) q.execute();
+	}
+
+	private boolean loadedState;
+	private ManagementState self;
+
+	@Required
+	public void setSelf(ManagementState self) {
+		this.self = self;
+	}
+
+	@PostConstruct
+	@WithinSingleTransaction
+	public void load() {
+		if (loadedState || !isPersistent())
+			return;
+		WebappState state = get();
+		if (state == null)
+			return;
+		allowNewWorkflowRuns = state.getAllowNewWorkflowRuns();
+		logIncomingWorkflows = state.getLogIncomingWorkflows();
+		logOutgoingExceptions = state.getLogOutgoingExceptions();
+		usageRecordLogFile = state.getUsageRecordLogFile();
+		loadedState = true;
+	}
+
+	@WithinSingleTransaction
+	public void store() {
+		if (!isPersistent())
+			return;
+		WebappState state = get();
+		if (state == null) {
+			state = new WebappState();
+			// save state
+			state.id = KEY; // whatever...
+			state = persist(state);
+		}
+		state.setAllowNewWorkflowRuns(allowNewWorkflowRuns);
+		state.setLogIncomingWorkflows(logIncomingWorkflows);
+		state.setLogOutgoingExceptions(logOutgoingExceptions);
+		state.setUsageRecordLogFile(usageRecordLogFile);
+		loadedState = true;
+	}
+}
+
+// WARNING! If you change the name of this class, update persistence.xml as
+// well!
+@PersistenceCapable(table = "MANAGEMENTSTATE__WEBAPPSTATE")
+class WebappState implements ManagementModel {
+	public WebappState() {
+	}
+
+	@PrimaryKey
+	protected int id;
+
+	/** Whether we should log all workflows sent to us. */
+	@Persistent
+	private boolean logIncomingWorkflows;
+
+	/** Whether we allow the creation of new workflow runs. */
+	@Persistent
+	private boolean allowNewWorkflowRuns;
+
+	/**
+	 * Whether outgoing exceptions should be logged before being converted to
+	 * responses.
+	 */
+	@Persistent
+	private boolean logOutgoingExceptions;
+
+	/** Where to write usage records. */
+	@Persistent
+	private String usageRecordLogFile;
+
+	@Override
+	public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+		this.logIncomingWorkflows = logIncomingWorkflows;
+	}
+
+	@Override
+	public boolean getLogIncomingWorkflows() {
+		return logIncomingWorkflows;
+	}
+
+	@Override
+	public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+		this.allowNewWorkflowRuns = allowNewWorkflowRuns;
+	}
+
+	@Override
+	public boolean getAllowNewWorkflowRuns() {
+		return allowNewWorkflowRuns;
+	}
+
+	@Override
+	public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+		this.logOutgoingExceptions = logOutgoingExceptions;
+	}
+
+	@Override
+	public boolean getLogOutgoingExceptions() {
+		return logOutgoingExceptions;
+	}
+
+	@Override
+	public String getUsageRecordLogFile() {
+		return usageRecordLogFile;
+	}
+
+	@Override
+	public void setUsageRecordLogFile(String usageRecordLogFile) {
+		this.usageRecordLogFile = usageRecordLogFile;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
new file mode 100644
index 0000000..563a822
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunREST.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.Response.noContent;
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.joda.time.format.ISODateTimeFormat.dateTime;
+import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
+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.Status.Operating;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.Date;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.joda.time.DateTime;
+import org.ogf.usage.JobUsageRecord;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.RunBean;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.Status;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+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.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.InteractionFeedREST;
+import org.taverna.server.master.rest.TavernaServerInputREST;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.rest.TavernaServerRunREST;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * RESTful interface to a single workflow run.
+ * 
+ * @author Donal Fellows
+ */
+abstract class RunREST implements TavernaServerRunREST, RunBean {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private String runName;
+	private TavernaRun run;
+	private TavernaServerSupport support;
+	private ContentsDescriptorBuilder cdBuilder;
+
+	@Override
+	@Required
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	@Required
+	public void setCdBuilder(ContentsDescriptorBuilder cdBuilder) {
+		this.cdBuilder = cdBuilder;
+	}
+
+	@Override
+	public void setRunName(String runName) {
+		this.runName = runName;
+	}
+
+	@Override
+	public void setRun(TavernaRun run) {
+		this.run = run;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public RunDescription getDescription(UriInfo ui) {
+		return new RunDescription(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response destroy() throws NoUpdateException {
+		try {
+			support.unregisterRun(runName, run);
+		} catch (UnknownRunException e) {
+			log.fatal("can't happen", e);
+		}
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerListenersREST getListeners() {
+		return makeListenersInterface().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerSecurityREST getSecurity() throws NotOwnerException {
+		TavernaSecurityContext secContext = run.getSecurityContext();
+		if (!support.getPrincipal().equals(secContext.getOwner()))
+			throw new NotOwnerException();
+
+		// context.getBean("run.security", run, secContext);
+		return makeSecurityInterface().connect(secContext, run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getExpiryTime() {
+		return dateTime().print(new DateTime(run.getExpiry()));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getCreateTime() {
+		return dateTime().print(new DateTime(run.getCreationTimestamp()));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getFinishTime() {
+		Date f = run.getFinishTimestamp();
+		return f == null ? "" : dateTime().print(new DateTime(f));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStartTime() {
+		Date f = run.getStartTimestamp();
+		return f == null ? "" : dateTime().print(new DateTime(f));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStatus() {
+		return run.getStatus().toString();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Workflow getWorkflow() {
+		return run.getWorkflow();
+	}
+
+	@Override
+	@CallCounted
+	public String getMainProfileName() {
+		String name = run.getWorkflow().getMainProfileName();
+		return (name == null ? "" : name);
+	}
+
+	@Override
+	@CallCounted
+	public ProfileList getProfiles() {
+		return support.getProfileDescriptor(run.getWorkflow());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public DirectoryREST getWorkingDirectory() {
+		return makeDirectoryInterface().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setExpiryTime(String expiry) throws NoUpdateException,
+			IllegalArgumentException {
+		DateTime wanted = dateTimeParser().parseDateTime(expiry.trim());
+		Date achieved = support.updateExpiry(run, wanted.toDate());
+		return dateTime().print(new DateTime(achieved));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response setStatus(String status) throws NoUpdateException {
+		Status newStatus = Status.valueOf(status.trim());
+		support.permitUpdate(run);
+		if (newStatus == Operating && run.getStatus() == Initialized) {
+			if (!support.getAllowStartWorkflowRuns())
+				throw new OverloadedException();
+			String issue = run.setStatus(newStatus);
+			if (issue == null)
+				issue = "starting run...";
+			return status(202).entity(issue).type("text/plain").build();
+		}
+		run.setStatus(newStatus); // Ignore the result
+		return ok(run.getStatus().toString()).type("text/plain").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public TavernaServerInputREST getInputs(UriInfo ui) {
+		return makeInputInterface().connect(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getOutputFile() {
+		String o = run.getOutputBaclavaFile();
+		return o == null ? "" : o;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setOutputFile(String filename) throws NoUpdateException,
+			FilesystemAccessException, BadStateChangeException {
+		support.permitUpdate(run);
+		if (filename != null && filename.length() == 0)
+			filename = null;
+		run.setOutputBaclavaFile(filename);
+		String o = run.getOutputBaclavaFile();
+		return o == null ? "" : o;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public OutputDescription getOutputDescription(UriInfo ui)
+			throws BadStateChangeException, FilesystemAccessException,
+			NoDirectoryEntryException {
+		if (run.getStatus() == Initialized)
+			throw new BadStateChangeException(
+					"may not get output description in initial state");
+		return cdBuilder.makeOutputDescriptor(run, ui);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed({ USER, SELF })
+	public InteractionFeedREST getInteractionFeed() {
+		return makeInteractionFeed().connect(run);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getName() {
+		return run.getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String setName(String name) throws NoUpdateException {
+		support.permitUpdate(run);
+		run.setName(name);
+		return run.getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStdout() throws NoListenerException {
+		return support.getProperty(run, "io", "stdout");
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public String getStderr() throws NoListenerException {
+		return support.getProperty(run, "io", "stderr");
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getUsage() throws NoListenerException, JAXBException {
+		String ur = support.getProperty(run, "io", "usageRecord");
+		if (ur.isEmpty())
+			return noContent().build();
+		return ok(JobUsageRecord.unmarshal(ur), APPLICATION_XML).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getLogContents() {
+		FileConcatenation fc = support.getLogs(run);
+		if (fc.isEmpty())
+			return Response.noContent().build();
+		return Response.ok(fc, TEXT_PLAIN).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public Response getRunBundle() {
+		FileConcatenation fc = support.getProv(run);
+		if (fc.isEmpty())
+			return Response.status(404).entity("no provenance currently available").build();
+		return Response.ok(fc, "application/vnd.wf4ever.robundle+zip").build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public boolean getGenerateProvenance() {
+		return run.getGenerateProvenance();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	@RolesAllowed(USER)
+	public boolean setGenerateProvenance(boolean newValue) throws NoUpdateException {
+		support.permitUpdate(run);
+		run.setGenerateProvenance(newValue);
+		return run.getGenerateProvenance();
+	}
+
+	/**
+	 * Construct a RESTful interface to a run's filestore.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract DirectoryREST makeDirectoryInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's input descriptors.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract InputREST makeInputInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's listeners.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract ListenersREST makeListenersInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's security.
+	 * 
+	 * @return The handle to the interface, as decorated by Spring.
+	 */
+	protected abstract RunSecurityREST makeSecurityInterface();
+
+	/**
+	 * Construct a RESTful interface to a run's interaction feed.
+	 * 
+	 * @return The handle to the interaface, as decorated by Spring.
+	 */
+	protected abstract InteractionFeed makeInteractionFeed();
+
+	@Override
+	@CallCounted
+	public Response runOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response workflowOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response profileOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response expiryOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response createTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response startTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response finishTimeOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response statusOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response outputOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response nameOptions() {
+		return opt("PUT");
+	}
+
+	@Override
+	@CallCounted
+	public Response stdoutOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response stderrOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response usageOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response logOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response runBundleOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response generateProvenanceOptions() {
+		return opt("PUT");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
new file mode 100644
index 0000000..5a366b2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/RunSecurityREST.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static java.util.UUID.randomUUID;
+import static javax.ws.rs.core.Response.created;
+import static javax.ws.rs.core.Response.noContent;
+import static org.taverna.server.master.common.Status.Initialized;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.SecurityBean;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single workflow run's security settings.
+ * 
+ * @author Donal Fellows
+ */
+class RunSecurityREST implements TavernaServerSecurityREST, SecurityBean {
+	private TavernaServerSupport support;
+	private TavernaSecurityContext context;
+	private TavernaRun run;
+
+	@Override
+	public void setSupport(TavernaServerSupport support) {
+		this.support = support;
+	}
+
+	@Override
+	public RunSecurityREST connect(TavernaSecurityContext context,
+			TavernaRun run) {
+		this.context = context;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Descriptor describe(UriInfo ui) {
+		return new Descriptor(secure(ui).path("{element}"), context.getOwner()
+				.getName(), context.getCredentials(), context.getTrusted());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getOwner() {
+		return context.getOwner().getName();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialList listCredentials() {
+		return new CredentialList(context.getCredentials());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialHolder getParticularCredential(String id)
+			throws NoCredentialException {
+		for (Credential c : context.getCredentials())
+			if (c.id.equals(id))
+				return new CredentialHolder(c);
+		throw new NoCredentialException();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public CredentialHolder setParticularCredential(String id,
+			CredentialHolder cred, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Credential c = cred.credential;
+		c.id = id;
+		c.href = ui.getAbsolutePath().toString();
+		context.validateCredential(c);
+		context.deleteCredential(c);
+		context.addCredential(c);
+		return new CredentialHolder(c);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addCredential(CredentialHolder cred, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Credential c = cred.credential;
+		c.id = randomUUID().toString();
+		URI uri = secure(ui).path("{id}").build(c.id);
+		c.href = uri.toString();
+		context.validateCredential(c);
+		context.addCredential(c);
+		return created(uri).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteAllCredentials(UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		for (Credential c : context.getCredentials())
+			context.deleteCredential(c);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteCredential(String id, UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		context.deleteCredential(new Credential.Dummy(id));
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TrustList listTrusted() {
+		return new TrustList(context.getTrusted());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Trust getParticularTrust(String id) throws NoCredentialException {
+		for (Trust t : context.getTrusted())
+			if (t.id.equals(id))
+				return t;
+		throw new NoCredentialException();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Trust setParticularTrust(String id, Trust t, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		t.id = id;
+		t.href = ui.getAbsolutePath().toString();
+		context.validateTrusted(t);
+		context.deleteTrusted(t);
+		context.addTrusted(t);
+		return t;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response addTrust(Trust t, UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		t.id = randomUUID().toString();
+		URI uri = secure(ui).path("{id}").build(t.id);
+		t.href = uri.toString();
+		context.validateTrusted(t);
+		context.addTrusted(t);
+		return created(uri).build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteAllTrusts(UriInfo ui) throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		for (Trust t : context.getTrusted())
+			context.deleteTrusted(t);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deleteTrust(String id, UriInfo ui)
+			throws BadStateChangeException {
+		if (run.getStatus() != Initialized)
+			throw new BadStateChangeException();
+		Trust toDelete = new Trust();
+		toDelete.id = id;
+		context.deleteTrusted(toDelete);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public PermissionsDescription describePermissions(UriInfo ui) {
+		Map<String, Permission> perm = support.getPermissionMap(context);
+		return new PermissionsDescription(secure(ui).path("{id}"), perm);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Permission describePermission(String id) {
+		return support.getPermission(context, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Permission setPermission(String id, Permission perm) {
+		support.setPermission(context, id, perm);
+		return support.getPermission(context, id);
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response deletePermission(String id, UriInfo ui) {
+		support.setPermission(context, id, Permission.None);
+		return noContent().build();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public Response makePermission(PermissionDescription desc, UriInfo ui) {
+		support.setPermission(context, desc.userName, desc.permission);
+		return created(secure(ui).path("{user}").build(desc.userName)).build();
+	}
+
+	@Override
+	@CallCounted
+	public Response descriptionOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response ownerOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response credentialsOptions() {
+		return opt("POST", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response credentialOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response trustsOptions() {
+		return opt("POST", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response trustOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+
+	@Override
+	@CallCounted
+	public Response permissionsOptions() {
+		return opt("POST");
+	}
+
+	@Override
+	@CallCounted
+	public Response permissionOptions(String id) {
+		return opt("PUT", "DELETE");
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
new file mode 100644
index 0000000..6c9e8d8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/SingleListenerREST.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static java.util.Arrays.asList;
+import static org.taverna.server.master.common.Uri.secure;
+import static org.taverna.server.master.utils.RestUtils.opt;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.taverna.server.master.api.OneListenerBean;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.rest.TavernaServerListenersREST;
+import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.taverna.server.master.rest.TavernaServerListenersREST.TavernaServerListenerREST;
+import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
+import org.taverna.server.master.utils.InvocationCounter.CallCounted;
+
+/**
+ * RESTful interface to a single listener attached to a workflow run.
+ * 
+ * @author Donal Fellows
+ */
+abstract class SingleListenerREST implements TavernaServerListenerREST,
+		OneListenerBean {
+	private Listener listen;
+	private TavernaRun run;
+
+	@Override
+	public SingleListenerREST connect(Listener listen, TavernaRun run) {
+		this.listen = listen;
+		this.run = run;
+		return this;
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public String getConfiguration() {
+		return listen.getConfiguration();
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public ListenerDescription getDescription(UriInfo ui) {
+		return new ListenerDescription(listen, secure(ui));
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenersREST.Properties getProperties(UriInfo ui) {
+		return new TavernaServerListenersREST.Properties(secure(ui).path(
+				"{prop}"), listen.listProperties());
+	}
+
+	@Override
+	@CallCounted
+	@PerfLogged
+	public TavernaServerListenersREST.Property getProperty(
+			final String propertyName) throws NoListenerException {
+		List<String> p = asList(listen.listProperties());
+		if (p.contains(propertyName)) {
+			return makePropertyInterface().connect(listen, run, propertyName);
+		}
+		throw new NoListenerException("no such property");
+	}
+
+	protected abstract ListenerPropertyREST makePropertyInterface();
+
+	@Override
+	@CallCounted
+	public Response listenerOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response configurationOptions() {
+		return opt();
+	}
+
+	@Override
+	@CallCounted
+	public Response propertiesOptions() {
+		return opt();
+	}
+}


[47/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/wadl/tavserv.wadl
----------------------------------------------------------------------
diff --git a/server-client/src/main/wadl/tavserv.wadl b/server-client/src/main/wadl/tavserv.wadl
deleted file mode 100644
index 2ba8fbe..0000000
--- a/server-client/src/main/wadl/tavserv.wadl
+++ /dev/null
@@ -1,591 +0,0 @@
-<application xmlns="http://wadl.dev.java.net/2009/02"
-	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:prefix1="http://ns.taverna.org.uk/2010/xml/server/rest/"
-	xmlns:prefix3="http://ns.taverna.org.uk/2010/xml/server/"
-	xmlns:prefix10="http://ns.taverna.org.uk/2010/port/" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
-	xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" jxb:version="2.1">
-<grammars>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:admin="http://ns.taverna.org.uk/2010/xml/server/admin/" xmlns:feed="http://ns.taverna.org.uk/2010/xml/server/feed/" xmlns:port="http://ns.taverna.org.uk/2010/port/" xmlns:tns="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts-rest="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts-soap="http://ns.taverna.org.uk/2010/xml/server/soap/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/xml/server/rest/" jxb:version="2.1">
-    <xs:annotation>
-    	<xs:appinfo>
-			<jxb:schemaBindings>
-				<jxb:package name="uk.org.taverna.server.client.rest" />
-			</jxb:schemaBindings>
-    	</xs:appinfo>
-    </xs:annotation>
-    <xs:import namespace="http://ns.taverna.org.uk/2010/xml/server/"/>
-    <xs:import namespace="http://www.w3.org/1999/xlink"/>
-    <xs:element name="capabilities">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element maxOccurs="unbounded" minOccurs="0" name="capability" type="ts:Capability"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="credential" type="ts-rest:Credential"/>
-    <xs:element name="credentials" type="ts-rest:credentialList"/>
-    <xs:element name="directoryContents" type="ts-rest:DirectoryContents"/>
-    <xs:element name="enabledNotificationFabrics">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element maxOccurs="unbounded" minOccurs="0" name="notifier" type="xs:string"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="filesystemOperation" type="ts-rest:FilesystemCreationOperation"/>
-    <xs:element name="listenerDefinition" type="ts-rest:ListenerDefinition"/>
-    <xs:element name="listenerDescription" type="ts-rest:ListenerDescription"/>
-    <xs:element name="listeners">
-        <xs:complexType>
-            <xs:complexContent>
-                <xs:extension base="ts:VersionedElement">
-                    <xs:sequence>
-                        <xs:element maxOccurs="unbounded" minOccurs="0" name="listener" type="ts-rest:ListenerDescription"/>
-                    </xs:sequence>
-                </xs:extension>
-            </xs:complexContent>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="mkdir" type="ts-rest:MakeDirectory"/>
-    <xs:element name="permissionUpdate" type="ts-rest:permissionDescription"/>
-    <xs:element name="permissionsDescriptor" type="ts-rest:permissionsDescription"/>
-    <xs:element name="permittedListeners">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element maxOccurs="unbounded" minOccurs="0" name="type" type="xs:string"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="permittedWorkflows">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element maxOccurs="unbounded" minOccurs="0" name="workflow" type="xs:string"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="policyDescription">
-        <xs:complexType>
-            <xs:complexContent>
-                <xs:extension base="ts:VersionedElement">
-                    <xs:sequence>
-                        <xs:element minOccurs="0" name="runLimit" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="operatingLimit" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="permittedWorkflows" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="permittedListenerTypes" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="enabledNotificationFabrics" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="capabilities" type="ts:Location"/>
-                    </xs:sequence>
-                </xs:extension>
-            </xs:complexContent>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="properties">
-        <xs:complexType>
-            <xs:complexContent>
-                <xs:extension base="ts:VersionedElement">
-                    <xs:sequence>
-                        <xs:element maxOccurs="unbounded" minOccurs="0" name="property" type="ts-rest:PropertyDescription"/>
-                    </xs:sequence>
-                </xs:extension>
-            </xs:complexContent>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="runDescription">
-        <xs:complexType>
-            <xs:complexContent>
-                <xs:extension base="ts:VersionedElement">
-                    <xs:sequence>
-                        <xs:element minOccurs="0" name="expiry">
-                            <xs:complexType>
-                                <xs:simpleContent>
-                                    <xs:extension base="xs:string">
-                                        <xs:attribute ref="xlink:href"/>
-                                    </xs:extension>
-                                </xs:simpleContent>
-                            </xs:complexType>
-                        </xs:element>
-                        <xs:element minOccurs="0" name="creationWorkflow" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="createTime" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="startTime" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="finishTime" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="status" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="workingDirectory" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="inputs" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="output" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="securityContext" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="listeners">
-                            <xs:complexType>
-                                <xs:complexContent>
-                                    <xs:extension base="ts:Location">
-                                        <xs:sequence>
-                                            <xs:element maxOccurs="unbounded" minOccurs="0" name="listener" nillable="true" type="ts:Location"/>
-                                        </xs:sequence>
-                                    </xs:extension>
-                                </xs:complexContent>
-                            </xs:complexType>
-                        </xs:element>
-                        <xs:element minOccurs="0" name="interaction" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="name" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="stdout" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="stderr" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="usage" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="log" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="run-bundle" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="generate-provenance" type="ts:Location"/>
-                    </xs:sequence>
-                    <xs:attribute ref="ts-rest:owner"/>
-                </xs:extension>
-            </xs:complexContent>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="runInput" type="ts-rest:InputDescription"/>
-    <xs:element name="runInputs" type="ts-rest:TavernaRunInputs"/>
-    <xs:element name="runList">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element maxOccurs="unbounded" minOccurs="0" name="run" type="ts:TavernaRun"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="securityDescriptor" type="ts-rest:SecurityDescriptor"/>
-    <xs:element name="serverDescription">
-        <xs:complexType>
-            <xs:complexContent>
-                <xs:extension base="ts:VersionedElement">
-                    <xs:sequence>
-                        <xs:element minOccurs="0" name="runs" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="policy" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="feed" type="ts:Location"/>
-                        <xs:element minOccurs="0" name="interactionFeed" type="ts:Location"/>
-                    </xs:sequence>
-                </xs:extension>
-            </xs:complexContent>
-        </xs:complexType>
-    </xs:element>
-    <xs:element name="trustedIdentities" type="ts-rest:trustList"/>
-    <xs:element name="upload" type="ts-rest:UploadFile"/>
-    <xs:element name="userPermission" type="ts-rest:linkedPermissionDescription"/>
-    <xs:complexType name="InputDescription">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:choice minOccurs="0">
-                        <xs:element name="file">
-                            <xs:complexType>
-                                <xs:simpleContent>
-                                    <xs:extension base="ts-rest:InputContents"/>
-                                </xs:simpleContent>
-                            </xs:complexType>
-                        </xs:element>
-                        <xs:element name="reference">
-                            <xs:complexType>
-                                <xs:simpleContent>
-                                    <xs:extension base="ts-rest:InputContents"/>
-                                </xs:simpleContent>
-                            </xs:complexType>
-                        </xs:element>
-                        <xs:element name="value">
-                            <xs:complexType>
-                                <xs:simpleContent>
-                                    <xs:extension base="ts-rest:InputContents"/>
-                                </xs:simpleContent>
-                            </xs:complexType>
-                        </xs:element>
-                    </xs:choice>
-                </xs:sequence>
-                <xs:attribute ref="ts-rest:name"/>
-                <xs:attribute ref="ts-rest:descriptorRef"/>
-                <xs:attribute ref="ts-rest:listDelimiter"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:simpleType name="InputContents">
-        <xs:restriction base="xs:string"/>
-    </xs:simpleType>
-    <xs:complexType name="ListenerDescription">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element minOccurs="0" name="configuration" type="ts:Location"/>
-                    <xs:element minOccurs="0" name="properties">
-                        <xs:complexType>
-                            <xs:sequence>
-                                <xs:element maxOccurs="unbounded" minOccurs="0" name="property" type="ts-rest:PropertyDescription"/>
-                            </xs:sequence>
-                        </xs:complexType>
-                    </xs:element>
-                </xs:sequence>
-                <xs:attribute ref="xlink:href"/>
-                <xs:attribute ref="ts-rest:name"/>
-                <xs:attribute ref="ts-rest:type"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="PropertyDescription">
-        <xs:complexContent>
-            <xs:extension base="ts:Location">
-                <xs:sequence/>
-                <xs:attribute ref="ts-rest:name"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="TavernaRunInputs">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element minOccurs="0" name="expected" type="ts:Location"/>
-                    <xs:element minOccurs="0" name="baclava" type="ts:Location"/>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" name="input" nillable="true" type="ts:Location"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="Credential">
-        <xs:choice>
-            <xs:element ref="ts:keypair"/>
-            <xs:element ref="ts:userpass"/>
-        </xs:choice>
-    </xs:complexType>
-    <xs:complexType name="DirectoryContents">
-        <xs:sequence>
-            <xs:choice maxOccurs="unbounded" minOccurs="0">
-                <xs:element ref="ts:dir"/>
-                <xs:element ref="ts:file"/>
-            </xs:choice>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType name="FilesystemCreationOperation">
-        <xs:simpleContent>
-            <xs:extension base="xs:base64Binary">
-                <xs:attribute ref="ts-rest:name"/>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="MakeDirectory">
-        <xs:simpleContent>
-            <xs:extension base="ts-rest:FilesystemCreationOperation"/>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="UploadFile">
-        <xs:simpleContent>
-            <xs:extension base="ts-rest:FilesystemCreationOperation"/>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="permissionsDescription">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" name="permission" type="ts-rest:linkedPermissionDescription"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="linkedPermissionDescription">
-        <xs:complexContent>
-            <xs:extension base="ts:Location">
-                <xs:sequence>
-                    <xs:element minOccurs="0" name="userName" type="xs:string"/>
-                    <xs:element minOccurs="0" name="permission" type="ts:Permission"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="trustList">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" name="trust" type="ts:TrustDescriptor"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="permissionDescription">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="userName" type="xs:string"/>
-            <xs:element minOccurs="0" name="permission" type="ts:Permission"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="SecurityDescriptor">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element minOccurs="0" name="owner" type="xs:string"/>
-                    <xs:element minOccurs="0" name="permissions" type="ts:Location"/>
-                    <xs:element minOccurs="0" name="credentials" type="ts-rest:CredentialCollection"/>
-                    <xs:element minOccurs="0" name="trusts" type="ts-rest:TrustCollection"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="CredentialCollection">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" minOccurs="0" ref="ts-rest:credential"/>
-        </xs:sequence>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="TrustCollection">
-        <xs:sequence>
-            <xs:element maxOccurs="unbounded" minOccurs="0" name="trust" type="ts:TrustDescriptor"/>
-        </xs:sequence>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="credentialList">
-        <xs:complexContent>
-            <xs:extension base="ts:VersionedElement">
-                <xs:sequence>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" ref="ts-rest:credential"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="ListenerDefinition">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute ref="ts-rest:type"/>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:attribute name="descriptorRef" type="xs:anyURI"/>
-    <xs:attribute name="listDelimiter" type="xs:string"/>
-    <xs:attribute name="name" type="xs:string"/>
-    <xs:attribute name="owner" type="xs:string"/>
-    <xs:attribute name="type" type="xs:string"/>
-</xs:schema>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xlink" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://www.w3.org/1999/xlink" jxb:version="2.1">
-    <xs:attribute name="href" type="xs:string"/>
-</xs:schema>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:port="http://ns.taverna.org.uk/2010/port/" xmlns:run="http://ns.taverna.org.uk/2010/run/" xmlns:tns="http://ns.taverna.org.uk/2010/port/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/port/" jxb:version="2.1">
-    <xs:annotation>
-    	<xs:appinfo>
-			<jxb:schemaBindings>
-				<jxb:package name="uk.org.taverna.server.client.generic.port" />
-			</jxb:schemaBindings>
-    	</xs:appinfo>
-    </xs:annotation>
-    <xs:import namespace="http://www.w3.org/1999/xlink"/>
-    <xs:element name="inputDescription" type="port:inputDescription"/>
-    <xs:element name="workflowOutputs" type="port:outputDescription"/>
-    <xs:complexType name="outputDescription">
-        <xs:complexContent>
-            <xs:extension base="port:PortDescription">
-                <xs:sequence>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" name="output" type="port:OutputPort"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType abstract="true" name="PortDescription">
-        <xs:sequence/>
-        <xs:attribute ref="port:workflowId"/>
-        <xs:attribute ref="port:workflowRun"/>
-        <xs:attribute ref="port:workflowRunId"/>
-    </xs:complexType>
-    <xs:complexType name="OutputPort">
-        <xs:complexContent>
-            <xs:extension base="port:Port">
-                <xs:choice>
-                    <xs:element name="value" type="port:LeafValue"/>
-                    <xs:element name="list" type="port:ListValue"/>
-                    <xs:element name="error" type="port:ErrorValue"/>
-                    <xs:element name="absent" type="port:AbsentValue"/>
-                </xs:choice>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="Port">
-        <xs:sequence/>
-        <xs:attribute ref="port:name" use="required"/>
-        <xs:attribute ref="port:depth"/>
-    </xs:complexType>
-    <xs:complexType name="LeafValue">
-        <xs:complexContent>
-            <xs:extension base="port:Value">
-                <xs:sequence/>
-                <xs:attribute ref="port:contentFile"/>
-                <xs:attribute ref="port:contentType"/>
-                <xs:attribute ref="port:contentByteLength"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType abstract="true" name="Value">
-        <xs:sequence/>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:complexType name="ErrorValue">
-        <xs:complexContent>
-            <xs:extension base="port:Value">
-                <xs:sequence/>
-                <xs:attribute ref="port:depth"/>
-                <xs:attribute ref="port:errorFile"/>
-                <xs:attribute ref="port:errorByteLength"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="ListValue">
-        <xs:complexContent>
-            <xs:extension base="port:Value">
-                <xs:sequence>
-                    <xs:choice maxOccurs="unbounded" minOccurs="0">
-                        <xs:element name="value" type="port:LeafValue"/>
-                        <xs:element name="list" type="port:ListValue"/>
-                        <xs:element name="error" type="port:ErrorValue"/>
-                        <xs:element name="absent" type="port:AbsentValue"/>
-                    </xs:choice>
-                </xs:sequence>
-                <xs:attribute ref="port:length"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="AbsentValue">
-        <xs:complexContent>
-            <xs:extension base="port:Value">
-                <xs:sequence/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="inputDescription">
-        <xs:complexContent>
-            <xs:extension base="port:PortDescription">
-                <xs:sequence>
-                    <xs:element maxOccurs="unbounded" minOccurs="0" name="input" type="port:InputPort"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="InputPort">
-        <xs:complexContent>
-            <xs:extension base="port:Port">
-                <xs:sequence/>
-                <xs:attribute ref="xlink:href"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:attribute name="contentByteLength" type="xs:long"/>
-    <xs:attribute name="contentFile" type="xs:string"/>
-    <xs:attribute name="contentType" type="xs:string"/>
-    <xs:attribute name="depth" type="xs:int"/>
-    <xs:attribute name="errorByteLength" type="xs:long"/>
-    <xs:attribute name="errorFile" type="xs:string"/>
-    <xs:attribute name="length" type="xs:int"/>
-    <xs:attribute name="name" type="xs:ID"/>
-    <xs:attribute name="workflowId" type="xs:string"/>
-    <xs:attribute name="workflowRun" type="xs:anyURI"/>
-    <xs:attribute name="workflowRunId" type="xs:string"/>
-</xs:schema>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:admin="http://ns.taverna.org.uk/2010/xml/server/admin/" xmlns:feed="http://ns.taverna.org.uk/2010/xml/server/feed/" xmlns:tns="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts="http://ns.taverna.org.uk/2010/xml/server/" xmlns:ts-rest="http://ns.taverna.org.uk/2010/xml/server/rest/" xmlns:ts-soap="http://ns.taverna.org.uk/2010/xml/server/soap/" xmlns:xlink="http://www.w3.org/1999/xlink" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://ns.taverna.org.uk/2010/xml/server/" jxb:version="2.1">
-    <xs:annotation>
-    	<xs:appinfo>
-			<jxb:schemaBindings>
-				<jxb:package name="uk.org.taverna.server.client.generic" />
-			</jxb:schemaBindings>
-    	</xs:appinfo>
-    </xs:annotation>
-    <xs:import namespace="http://www.w3.org/1999/xlink"/>
-    <xs:element name="capability" type="ts:Capability"/>
-    <xs:element name="dir" type="ts:DirectoryReference"/>
-    <xs:element name="file" type="ts:FileReference"/>
-    <xs:element name="keypair" type="ts:KeyPairCredential"/>
-    <xs:element name="runReference" type="ts:TavernaRun"/>
-    <xs:element name="trustedIdentity" type="ts:TrustDescriptor"/>
-    <xs:element name="userpass" type="ts:PasswordCredential"/>
-    <xs:element name="workflow" type="ts:Workflow"/>
-    <xs:complexType abstract="true" name="VersionedElement">
-        <xs:sequence/>
-        <xs:attribute ref="ts:serverVersion"/>
-        <xs:attribute ref="ts:serverRevision"/>
-        <xs:attribute ref="ts:serverBuildTimestamp"/>
-    </xs:complexType>
-    <xs:complexType name="Location">
-        <xs:sequence/>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:complexType name="Capability">
-        <xs:sequence/>
-        <xs:attribute ref="ts:capability"/>
-        <xs:attribute ref="ts:version"/>
-    </xs:complexType>
-    <xs:complexType name="KeyPairCredential">
-        <xs:complexContent>
-            <xs:extension base="ts:CredentialDescriptor">
-                <xs:sequence>
-                    <xs:element name="credentialName" type="xs:string"/>
-                    <xs:element minOccurs="0" name="credentialFile" type="xs:string"/>
-                    <xs:element minOccurs="0" name="fileType" type="xs:string"/>
-                    <xs:element minOccurs="0" name="unlockPassword" type="xs:string"/>
-                    <xs:element minOccurs="0" name="credentialBytes" type="xs:base64Binary"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType abstract="true" name="CredentialDescriptor">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="serviceURI" type="xs:anyURI"/>
-        </xs:sequence>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:complexType name="PasswordCredential">
-        <xs:complexContent>
-            <xs:extension base="ts:CredentialDescriptor">
-                <xs:sequence>
-                    <xs:element name="username" type="xs:string"/>
-                    <xs:element name="password" type="xs:string"/>
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-    <xs:complexType name="DirectoryEntry">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute ref="xlink:href"/>
-                <xs:attribute ref="ts:name"/>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="DirectoryReference">
-        <xs:simpleContent>
-            <xs:extension base="ts:DirectoryEntry"/>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="FileReference">
-        <xs:simpleContent>
-            <xs:extension base="ts:DirectoryEntry"/>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="TavernaRun">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute ref="xlink:href"/>
-                <xs:attribute ref="ts:serverVersion"/>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-    <xs:complexType name="Workflow">
-        <xs:sequence>
-            <xs:any maxOccurs="unbounded" minOccurs="0" namespace="##other" processContents="lax"/>
-        </xs:sequence>
-    </xs:complexType>
-    <xs:complexType final="extension restriction" name="TrustDescriptor">
-        <xs:sequence>
-            <xs:element minOccurs="0" name="certificateFile" type="xs:string"/>
-            <xs:element minOccurs="0" name="fileType" type="xs:string"/>
-            <xs:element minOccurs="0" name="certificateBytes" type="xs:base64Binary"/>
-            <xs:element maxOccurs="unbounded" minOccurs="0" name="serverName" type="xs:string"/>
-        </xs:sequence>
-        <xs:attribute ref="xlink:href"/>
-    </xs:complexType>
-    <xs:simpleType name="Permission">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="none"/>
-            <xs:enumeration value="read"/>
-            <xs:enumeration value="update"/>
-            <xs:enumeration value="destroy"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:attribute name="capability" type="xs:anyURI"/>
-    <xs:attribute name="name" type="xs:string"/>
-    <xs:attribute name="serverBuildTimestamp" type="xs:string"/>
-    <xs:attribute name="serverRevision" type="xs:string"/>
-    <xs:attribute name="serverVersion" type="xs:string"/>
-    <xs:attribute name="version" type="xs:string"/>
-</xs:schema>
-</grammars><resources base="http://example.com/taverna/rest"><resource path="/"><method name="GET"><doc>Produces the description of the service.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:serverDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the service.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="runs"><method name="GET"><doc>Produces a list of all runs visible to the user.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runList"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the operations on the collection of runs.</doc><response><representation mediaType="application/octet-stream"><
 /representation></response></method><method name="POST"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc><request><representation mediaType="application/vnd.taverna.t2flow+xml" element="prefix3:workflow"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc></representation><representation mediaType="application/xml" element="prefix3:workflow"><doc>Accepts (or not) a request to create a new run executing the given workflow.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Accepts a URL to a workflow to download and run. The URL must be hosted on a publicly-accessible service.</doc><request><representation mediaType="text/uri-list"><doc>Accepts a URL to a workflow to download and run. The URL must be hosted on a publicly-accessible service.</doc></representation></request><response><representation mediaType=
 "application/octet-stream"></representation></response></method></resource><resource path="/policy"><method name="GET"><doc>Describe the parts of this policy.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:policyDescription"></representation><representation mediaType="application/json"></representation></response></method><resource path="/capabilities"><method name="GET"><doc>Gets a description of the capabilities supported by this installation of Taverna Server.</doc><response><representation mediaType="application/xml" element="prefix1:capabilities"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/enabledNotificationFabrics"><method name="GET"><doc>Gets the list of supported, enabled notification fabrics. Each corresponds (approximately) to a protocol, e.g., email.</doc><response><representation mediaType="application/xml" element="prefix1:enabledNotificati
 onFabrics"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/operatingLimit"><method name="GET"><doc>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.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:int"><doc>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.</doc></param></representation></response></method></resource><resource path="/permittedListenerTypes"><method name="GET"><doc>Gets the list of permitted event listener types.</doc><response><representation mediaType="application/xml" element="prefix1:
 permittedListeners"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/permittedWorkflows"><method name="GET"><doc>Gets the list of permitted workflows.</doc><response><representation mediaType="application/xml" element="prefix1:permittedWorkflows"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/runLimit"><method name="GET"><doc>Gets the maximum number of simultaneous runs in any state that the user may create.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:int"><doc>Gets the maximum number of simultaneous runs in any state that the user may create.</doc></param></representation></response></method></resource></resource><resource path="/runs/{runName}"><doc>This represents how a Taverna Server workflow run looks to a RESTful API.</doc><param name="runName" style="template" type="x
 s:string"/><method name="DELETE"><doc>Deletes a workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Describes a workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/createTime"><method name="GET"><doc>Gives the time when the workflow run was first submitted to the server.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was first submitted to the server.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the d
 escription of the run create time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/expiry"><method name="GET"><doc>Gives the time when the workflow run becomes eligible for automatic deletion.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run becomes eligible for automatic deletion.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run expiry.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc></param><
 /representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Sets the time when the workflow run becomes eligible for automatic deletion.</doc></param></representation></response></method></resource><resource path="/finishTime"><method name="GET"><doc>Gives the time when the workflow run was first detected as finished, or an empty string if it has not yet finished (including if it has never started).</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was first detected as finished, or an empty string if it has not yet finished (including if it has never started).</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run finish time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="
 /generate-provenance"><method name="GET"><doc>Whether to create the run bundle for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Whether to create the run bundle for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Whether to create the run bundle for the workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:boolean"><doc>Whether to create the run bundle for the workflow run.</doc></param></representation></response></
 method></resource><resource path="/log"><method name="GET"><doc>Return the log for the workflow run.</doc><response><representation mediaType="text/plain"></representation></response></method><method name="OPTIONS"><doc>Return the log for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/name"><method name="GET"><doc>Gives the descriptive name of the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the descriptive name of the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the operations on the run&apos;s descriptive name.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitraril
 y truncated by the implementation.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitrarily truncated by the implementation.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Set the descriptive name of the workflow run. Note that this value may be arbitrarily truncated by the implementation.</doc></param></representation></response></method></resource><resource path="/output"><method name="GET"><doc>Gives the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></repre
 sentation></response></method><method name="GET"><doc>Gives a description of the outputs, as currently understood</doc><request></request><response><representation mediaType="application/xml" element="prefix10:workflowOutputs"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run output.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:st
 ring"><doc>Sets the Baclava file where output will be written; empty means use multiple simple files in the out directory.</doc></param></representation></response></method></resource><resource path="/run-bundle"><method name="GET"><doc>Return the run bundle for the workflow run.</doc><response><representation mediaType="application/vnd.wf4ever.robundle+zip"></representation></response></method><method name="OPTIONS"><doc>Return the run bundle for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/startTime"><method name="GET"><doc>Gives the time when the workflow run was started, or an empty string if the run has not yet started.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the time when the workflow run was started, or an empty string if the run has not yet started.</doc></param></representation></response></met
 hod><method name="OPTIONS"><doc>Produces the description of the run start time.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/status"><method name="GET"><doc>Gives the current status of the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the current status of the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run status.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Attempts to update the status of the workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Attempts to update the status of the workflow run.</doc></param></representation></request><response><representation mediaType="text/pla
 in"></representation></response></method></resource><resource path="/stderr"><method name="GET"><doc>Return the stderr for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Return the stderr for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Return the stderr for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/stdout"><method name="GET"><doc>Return the stdout for the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Return the stdout for the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Return the stdout for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resour
 ce><resource path="/usage"><method name="GET"><doc>Return the usage record for the workflow run.</doc><response><representation mediaType="application/xml"></representation></response></method><method name="OPTIONS"><doc>Return the usage record for the workflow run.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/workflow"><method name="GET"><doc>Gives the workflow document used to create the workflow run.</doc><response><representation mediaType="application/vnd.taverna.t2flow+xml" element="prefix3:workflow"></representation><representation mediaType="application/xml" element="prefix3:workflow"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run workflow.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/inp
 ut"><doc>This represents how a Taverna Server workflow run&apos;s inputs looks to a RESTful API.</doc><method name="GET"><doc>Describe the sub-URIs of this resource.</doc><response><representation mediaType="application/xml" element="prefix1:runInputs"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run&apos;s inputs&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/baclava"><method name="GET"><doc>Gives the Baclava file describing the inputs, or empty if individual files are used.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the Baclava file describing the inputs, or empty if individual files are used.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the inp
 uts&apos; baclava operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the Baclava file describing the inputs.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Sets the Baclava file describing the inputs.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Sets the Baclava file describing the inputs.</doc></param></representation></response></method></resource><resource path="/expected"><method name="GET"><doc>Describe the expected inputs of this workflow run.</doc><response><representation mediaType="application/xml" element="prefix10:inputDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the expected inputs&apos; operati
 ons.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/input/{name}"><param name="name" style="template" type="xs:string"/><method name="GET"><doc>Gives a description of what is used to supply a particular input.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:runInput"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the one input&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Sets the source for a particular input port.</doc><request><representation mediaType="application/xml" element="prefix1:runInput"><doc>Sets the source for a particular input port.</doc></representation><representation mediaType="application/json"><doc>Sets the
  source for a particular input port.</doc></representation></request><response><representation mediaType="application/xml" element="prefix1:runInput"></representation><representation mediaType="application/json"></representation></response></method></resource></resource><resource path="/interaction"><method name="GET"><doc>Get the feed document for this ATOM feed.</doc><response><representation mediaType="application/atom+xml"></representation></response></method><method name="OPTIONS"><doc>Describes what HTTP operations are supported on the feed.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Adds an entry to this ATOM feed.</doc><request><representation mediaType="application/atom+xml"><doc>Adds an entry to this ATOM feed.</doc></representation></request><response><representation mediaType="application/atom+xml"></representation></response></method><resource path="/{id}"><param name="id" style="temp
 late" type="xs:string"/><method name="DELETE"><doc>Deletes an entry from this ATOM feed.</doc><request></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Deletes an entry from this ATOM feed.</doc></param></representation></response></method><method name="GET"><doc>Get the entry with a particular ID within this ATOM feed.</doc><request></request><response><representation mediaType="application/atom+xml"></representation></response></method><method name="OPTIONS"><doc>Describes what HTTP operations are supported on an entry.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource></resource><resource path="/listeners"><doc>This represents all the event listeners attached to a workflow run.</doc><method name="GET"><doc>Get the listeners installed in the workflow run.</doc><request></request><response><representation mediaType="application/xml"
  element="prefix1:listeners"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run listeners&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Add a new event listener to the named workflow run.</doc><request><representation mediaType="application/xml" element="prefix1:listenerDefinition"><doc>Add a new event listener to the named workflow run.</doc></representation><representation mediaType="application/json"><doc>Add a new event listener to the named workflow run.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/{name}"><doc>This represents a single event listener attached to a workflow run.</doc><param name="name" style="template" type="xs:string"/><method name="GET"><doc>Get th
 e description of this listener.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:listenerDescription"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/configuration"><method name="GET"><doc>Get the configuration for the given event listener that is attached to a workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Get the configuration for the given event listener that is attached to a workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s configuration&apos;s operations.</doc><response><representation mediaType="applica
 tion/octet-stream"></representation></response></method></resource><resource path="/properties"><method name="GET"><doc>Get the list of properties supported by a given event listener attached to a workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:properties"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s properties&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/properties/{propertyName}"><doc>This represents a single property attached of an event listener.</doc><param name="propertyName" style="template" type="xs:string"/><method name="GET"><doc>Get the value of the particular property of an event listener attached to a workflow run.</doc><response><representation mediaType="text/plain"><param
  name="result" style="plain" type="xs:string"><doc>Get the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run listener&apos;s property&apos;s operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc><request><representation mediaType="text/plain"><param name="request" style="plain" type="xs:string"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></request><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Set the value of the particular property of an event listener attached to a workflow run.</doc></param></representation></response><
 /method></resource></resource></resource><resource path="/security"><doc>Manages the security of the workflow run. In general, only the owner of a run may access this resource.</doc><method name="GET"><doc>Gives a description of the security information supported by the workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:securityDescriptor"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run security.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><resource path="/credentials"><method name="DELETE"><doc>Deletes all credentials.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Gives a list of credentials supplied to this workflow run.</doc><response><representation
  mediaType="application/xml" element="prefix1:credentials"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run credentials&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Creates a new credential.</doc><request><representation mediaType="application/xml" element="prefix1:credential"><doc>Creates a new credential.</doc></representation><representation mediaType="application/json"><doc>Creates a new credential.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/credentials/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes a particular credential.</doc><request></request><response><representation mediaType="application/octet-stre
 am"></representation></response></method><method name="GET"><doc>Describes a particular credential.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:credential"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run credential&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates a particular credential.</doc><request><representation mediaType="application/xml" element="prefix1:credential"><doc>Updates a particular credential.</doc></representation><representation mediaType="application/json"><doc>Updates a particular credential.</doc></representation></request><response><representation mediaType="application/xml" element="prefix1:credential"></representation><representation mediaType="application/json"></represe
 ntation></response></method></resource><resource path="/owner"><method name="GET"><doc>Gives the identity of who owns the workflow run.</doc><response><representation mediaType="text/plain"><param name="result" style="plain" type="xs:string"><doc>Gives the identity of who owns the workflow run.</doc></param></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run owner.</doc><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/permissions"><method name="GET"><doc>Gives a list of all non-default permissions associated with the enclosing workflow run. By default, nobody has any access at all except for the owner of the run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:permissionsDescriptor"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Pro
 duces the description of the run permissions&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Creates a new assignment of permissions to a particular user.</doc><request><representation mediaType="application/xml" element="prefix1:permissionUpdate"><doc>Creates a new assignment of permissions to a particular user.</doc></representation><representation mediaType="application/json"><doc>Creates a new assignment of permissions to a particular user.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/permissions/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes (by resetting to default) the permissions associated with a particular user.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></
 response></method><method name="GET"><doc>Describes the permission granted to a particular user.</doc><request></request><response><representation mediaType="text/plain"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run permission&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates the permissions granted to a particular user.</doc><request><representation mediaType="text/plain"><doc>Updates the permissions granted to a particular user.</doc></representation></request><response><representation mediaType="text/plain"></representation></response></method></resource><resource path="/trusts"><method name="DELETE"><doc>Deletes all trusted identities.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Gives a list of trust
 ed identities supplied to this workflow run.</doc><response><representation mediaType="application/xml" element="prefix1:trustedIdentities"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the run trusted certificates&apos; operations.</doc><response><representation mediaType="application/octet-stream"></representation></response></method><method name="POST"><doc>Adds a new trusted identity.</doc><request><representation mediaType="application/xml" element="prefix3:trustedIdentity"><doc>Adds a new trusted identity.</doc></representation><representation mediaType="application/json"><doc>Adds a new trusted identity.</doc></representation></request><response><representation mediaType="application/octet-stream"></representation></response></method></resource><resource path="/trusts/{id}"><param name="id" style="template" type="xs:string"/><method name="DELETE"><doc>Deletes a particu
 lar trusted identity.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="GET"><doc>Describes a particular trusted identity.</doc><request></request><response><representation mediaType="application/xml" element="prefix3:trustedIdentity"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of one run trusted certificate&apos;s operations.</doc><request></request><response><representation mediaType="application/octet-stream"></representation></response></method><method name="PUT"><doc>Updates a particular trusted identity.</doc><request><representation mediaType="application/xml" element="prefix3:trustedIdentity"><doc>Updates a particular trusted identity.</doc></representation><representation mediaType="application/json"><doc>Updates a particular trusted identity.</doc></representation></request><respo
 nse><representation mediaType="application/xml" element="prefix3:trustedIdentity"></representation><representation mediaType="application/json"></representation></response></method></resource></resource><resource path="/wd"><doc>Representation of how a workflow run&apos;s working directory tree looks.</doc><method name="GET"><doc>Describes the working directory of the workflow run.</doc><request></request><response><representation mediaType="application/xml" element="prefix1:directoryContents"></representation><representation mediaType="application/json"></representation></response></method><resource path="/{path:(.*)}"><param name="path" style="template" repeating="true"/><method name="POST"><doc>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.</doc><request><representation mediaType="text/uri-list"><doc>Creates or updates a file in a particular location beneath the working directory o
 f the workflow run with the contents of a publicly readable URL.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="PUT"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc><request><representation mediaType="application/octet-stream"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc></representation><representation mediaType="*/*"><doc>Creates or updates a file in a particular location beneath the working directory of the workflow run.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/{path:.*}"><param name="path" style="template" repeating="true"/><method 
 name="DELETE"><doc>Deletes a file or directory that is in or below the working directory of a workflow run.</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="OPTIONS"><doc>Produces the description of the files/directories&apos; baclava operations.</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method><method name="POST"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or creates or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc><request><representation mediaType="application/xml" element="prefix1:filesystemOperation"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or create
 s or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc></representation><representation mediaType="application/json"><doc>Creates a directory in the filesystem beneath the working directory of the workflow run, or creates or updates a file&apos;s contents, where that file is in or below the working directory of a workflow run.</doc></representation></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation></response></method></resource><resource path="/{path:.+}"><param name="path" style="template" repeating="true"/><method name="GET"><doc>Gives a description of the named entity in or beneath the working directory of the workflow run (either a Directory or File).</doc><request></request><response><representation mediaType="application/xml"></representation><representation mediaType="application/json"></representation><representation mediaTyp
 e="application/octet-stream"></representation><representation mediaType="application/zip"></representation><representation mediaType="*/*"></representation></response></method></resource></resource></resource></resource></resources></application>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-distribution/pom.xml
----------------------------------------------------------------------
diff --git a/server-distribution/pom.xml b/server-distribution/pom.xml
deleted file mode 100644
index 8939dbf..0000000
--- a/server-distribution/pom.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-distribution</artifactId>
-	<name>Apache Taverna Server Distribution Packaging</name>
-	<packaging>pom</packaging>
-
-	<dependencies>
-		<dependency>
-			<groupId>${project.parent.version}</groupId>
-			<artifactId>taverna-server-webapp</artifactId>
-			<version>${project.parent.version}</version>
-			<type>war</type>
-		</dependency>
-	</dependencies>
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-assembly-plugin</artifactId>
-				<configuration>
-					<finalName>TavernaServer-${project.parent.version}</finalName>
-					<descriptors>
-						<descriptor>src/assemble/dist.xml</descriptor>
-					</descriptors>
-				</configuration>
-				<executions>
-					<execution>
-						<id>make-t2server-distribution</id>
-						<phase>package</phase>
-						<goals>
-							<goal>single</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-source-plugin</artifactId>
-				<executions>
-					<execution>
-						<id>default</id>
-						<phase>none</phase>
-					</execution>
-				</executions>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-jar-plugin</artifactId>
-				<executions>
-					<execution>
-						<id>default</id>
-						<phase>none</phase>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
-	<reporting>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-project-info-reports-plugin</artifactId>
-				<version>2.4</version>
-				<reportSets>
-					<reportSet>
-						<reports>
-							<!-- Only generate the index, nothing else. -->
-							<report>index</report>
-						</reports>
-					</reportSet>
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-javadoc-plugin</artifactId>
-				<version>2.8</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-changelog-plugin</artifactId>
-				<version>2.2</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-changes-plugin</artifactId>
-				<version>2.6</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-checkstyle-plugin</artifactId>
-				<version>2.7</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-pmd-plugin</artifactId>
-				<version>2.5</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-surefire-report-plugin</artifactId>
-				<version>2.9</version>
-				<reportSets>
-					<reportSet />
-				</reportSets>
-			</plugin>
-		</plugins>
-	</reporting>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-distribution/src/assemble/dist.xml
----------------------------------------------------------------------
diff --git a/server-distribution/src/assemble/dist.xml b/server-distribution/src/assemble/dist.xml
deleted file mode 100644
index a77883c..0000000
--- a/server-distribution/src/assemble/dist.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<assembly
-	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
-	<id>distribution</id>
-	<formats>
-		<format>zip</format>
-	</formats>
-<!-- 
-	<dependencySets>
-		<dependencySet>
-			<useTransitiveDependencies>false</useTransitiveDependencies>
-			<useProjectArtifact>false</useProjectArtifact>
-			<unpack>false</unpack>
-			<scope>runtime</scope>
-			<fileMode>0644</fileMode>
-		</dependencySet>
-	</dependencySets>
-	<fileSets>
-		<fileSet>
-			<includes>
-				<include>*.html</include>
-				<include>*.xml</include>
-				<include>*.txt</include>
-				<include>*.pdf</include>
-			</includes>
-			<excludes>
-				<exclude>pom.xml</exclude>
-			</excludes>
-		</fileSet>
-	</fileSets>
--->
-	<fileSets>
-		<fileSet>
-			<directory>${project.parent.basedir}</directory>
-			<includes>
-				<include>*.xml</include>
-				<include>*.txt</include>
-				<include>*.pdf</include>
-			</includes>
-			<excludes>
-				<exclude>pom.xml</exclude>
-			</excludes>
-			<fileMode>0644</fileMode>
-			<outputDirectory>.</outputDirectory>
-		</fileSet>
-		<fileSet>
-			<directory>${project.parent.basedir}/server-webapp/target</directory>
-			<includes>
-				<include>*.war</include>
-			</includes>
-			<outputDirectory>.</outputDirectory>
-			<fileMode>0644</fileMode>
-		</fileSet>
-	</fileSets>
-<!-- 
-	<moduleSets>
-		<moduleSet>
-			<includes>
-				<include>uk.org.taverna.server:server</include>
-			</includes>
-			<sources>
-				<fileSets>
-					<fileSet>
-						<includes>
-							<include>*.html</include>
-							<include>*.txt</include>
-						</includes>
-					</fileSet>
-				</fileSets>
-			</sources>
-		</moduleSet>
-		<moduleSet>
-			<includes>
-				<include>uk.org.taverna.server:server-webapp</include>
-			</includes>
-			<binaries />
-		</moduleSet>
-	</moduleSets>
--->
-</assembly>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-execution-delegate/pom.xml
----------------------------------------------------------------------
diff --git a/server-execution-delegate/pom.xml b/server-execution-delegate/pom.xml
deleted file mode 100644
index 59c8aff..0000000
--- a/server-execution-delegate/pom.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-execution-delegate</artifactId>
-	<packaging>bundle</packaging>
-	<name>Apache Taverna Server Reporting Probe</name>
-	<dependencies>
-		<dependency>
-			<groupId>org.apache.taverna.engine</groupId>
-			<artifactId>taverna-execution-api</artifactId>
-			<version>${taverna.engine.version}</version>
-			<type>bundle</type>
-		</dependency>
-		<dependency>
-			<groupId>junit</groupId>
-			<artifactId>junit</artifactId>
-			<scope>test</scope>
-		</dependency>
-	</dependencies>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
----------------------------------------------------------------------
diff --git a/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java b/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
deleted file mode 100644
index 7ea9998..0000000
--- a/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/ExecutionDelegate.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package org.taverna.server.execution_delegate;
-
-import java.net.URI;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Map;
-
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.datatype.DatatypeFactory;
-import javax.xml.datatype.XMLGregorianCalendar;
-
-import org.taverna.server.execution_delegate.RemoteExecution.ProcessorReportDocument.Property;
-
-import uk.org.taverna.platform.data.api.Data;
-import uk.org.taverna.platform.data.api.DataLocation;
-import uk.org.taverna.platform.execution.api.Execution;
-import uk.org.taverna.platform.report.ActivityReport;
-import uk.org.taverna.platform.report.ProcessorReport;
-import uk.org.taverna.platform.report.StatusReport;
-import uk.org.taverna.platform.report.WorkflowReport;
-import uk.org.taverna.scufl2.api.common.AbstractNamed;
-
-public class ExecutionDelegate extends UnicastRemoteObject implements
-		RemoteExecution {
-	private Execution delegated;
-	private DatatypeFactory dtf;
-
-	public ExecutionDelegate(Execution execution) throws RemoteException,
-			DatatypeConfigurationException {
-		super();
-		delegated = execution;
-		dtf = DatatypeFactory.newInstance();
-	}
-
-	@Override
-	public String getID() {
-		return delegated.getID();
-	}
-
-	@Override
-	public void delete() {
-		delegated.delete();
-	}
-
-	@Override
-	public void start() {
-		delegated.start();
-	}
-
-	@Override
-	public void pause() {
-		delegated.pause();
-	}
-
-	@Override
-	public void resume() {
-		delegated.resume();
-	}
-
-	@Override
-	public void cancel() {
-		delegated.cancel();
-	}
-
-	private XMLGregorianCalendar date(Date d) {
-		if (d == null)
-			return null;
-		GregorianCalendar c = new GregorianCalendar();
-		c.setTime(d);
-		return dtf.newXMLGregorianCalendar(c);
-	}
-
-	private <R extends ReportDocument, T extends AbstractNamed> R init(
-			R snapshot, StatusReport<T, ?, ?> report) {
-		snapshot.created = date(report.getCreatedDate());
-		snapshot.completed = date(report.getCompletedDate());
-		snapshot.cancelled = date(report.getCancelledDate());
-		snapshot.failed = date(report.getFailedDate());
-		snapshot.started = date(report.getStartedDate());
-		for (Date d : report.getPausedDates())
-			snapshot.paused.add(date(d));
-		for (Date d : report.getResumedDates())
-			snapshot.resumed.add(date(d));
-		snapshot.subject = report.getSubject().getName();
-		snapshot.state = report.getState().toString();
-		return snapshot;
-	}
-
-	private WorkflowReportDocument getReport(WorkflowReport report) {
-		WorkflowReportDocument snapshot = init(new WorkflowReportDocument(),
-				report);
-		for (ProcessorReport pr : report.getChildReports())
-			snapshot.processor.add(getReport(pr));
-		initMap(snapshot.inputs, report.getInputs());
-		initMap(snapshot.outputs, report.getOutputs());
-		return snapshot;
-	}
-
-	private void initMap(ArrayList<PortMapping> snapshot, Map<String, ?> report) {
-		for (String port : report.keySet())
-			snapshot.add(data(port, report.get(port)));
-	}
-
-	private static final String DEFAULT_PROPERTY_STRING = "";
-
-	private PortMapping data(String name, Object o) {
-		String loc;
-		if (o instanceof DataLocation) {
-			DataLocation d = (DataLocation) o;
-			loc = d.getDataServiceURI() + "#" + d.getDataID();
-		} else {
-			Data d = (Data) o;
-			loc = null;
-			if (d.hasReferences()) {
-				try {
-					loc = d.getReferences().iterator().next().getURI()
-							.toString();
-				} catch (Exception e) {
-				}
-			}
-			if (loc == null) {
-				DataLocation dl = d.getDataService().getDataLocation(d);
-				loc = dl.getDataServiceURI() + "#" + dl.getDataID();
-			}
-		}
-		return new PortMapping(name, URI.create(loc));
-	}
-
-	private ProcessorReportDocument getReport(ProcessorReport report) {
-		ProcessorReportDocument snapshot = init(new ProcessorReportDocument(),
-				report);
-		for (ActivityReport pr : report.getChildReports())
-			snapshot.activity.add(getReport(pr));
-		snapshot.jobsQueued = report.getJobsStarted();
-		snapshot.jobsStarted = report.getJobsStarted();
-		snapshot.jobsCompleted = report.getJobsCompleted();
-		snapshot.jobsErrored = report.getJobsCompletedWithErrors();
-		for (String key : report.getPropertyKeys()) {
-			Object value = report.getProperty(key);
-			if (value instanceof String || value instanceof Number)
-				snapshot.properties.add(new Property(key, value.toString()));
-			else
-				snapshot.properties.add(new Property(key,
-						DEFAULT_PROPERTY_STRING));
-		}
-		return snapshot;
-	}
-
-	private ActivityReportDocument getReport(ActivityReport report) {
-		ActivityReportDocument snapshot = init(new ActivityReportDocument(),
-				report);
-		for (WorkflowReport pr : report.getChildReports())
-			snapshot.workflow.add(getReport(pr));
-		initMap(snapshot.inputs, report.getInputs());
-		initMap(snapshot.outputs, report.getOutputs());
-		return snapshot;
-	}
-
-	@Override
-	public WorkflowReportDocument getWorkflowReport() {
-		return getReport(delegated.getWorkflowReport());
-	}
-}
-
-// ExecutionDelegate.java:[96,2]
-// initMap(java.util.ArrayList<org.taverna.server.execution_delegate.RemoteExecution.PortMapping>,java.util.Map<java.lang.String,uk.org.taverna.platform.data.api.Data>)
-// in org.taverna.server.execution_delegate.ExecutionDelegate cannot be applied
-// to
-// (java.util.ArrayList<org.taverna.server.execution_delegate.RemoteExecution.PortMapping>,java.util.Map<java.lang.String,uk.org.taverna.platform.data.api.DataLocation>)

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
----------------------------------------------------------------------
diff --git a/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java b/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
deleted file mode 100644
index b8510df..0000000
--- a/server-execution-delegate/src/main/java/org/taverna/server/execution_delegate/RemoteExecution.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package org.taverna.server.execution_delegate;
-
-import static javax.xml.bind.annotation.XmlAccessType.NONE;
-
-import java.net.URI;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlAccessorType;
-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.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-import javax.xml.bind.annotation.XmlValue;
-import javax.xml.datatype.XMLGregorianCalendar;
-
-/**
- * Interface for a single execution of a Taverna workflow in a remote process.
- * 
- * @author David Withers
- */
-public interface RemoteExecution extends Remote {
-
-	/**
-	 * Returns the identifier for this execution.
-	 * 
-	 * @return the identifier for this execution
-	 */
-	String getID() throws RemoteException;
-
-	/**
-	 * Returns the <code>WorkflowReport</code> for the execution.
-	 * 
-	 * @return the <code>WorkflowReport</code> for the execution
-	 */
-	WorkflowReportDocument getWorkflowReport() throws RemoteException;
-
-	/**
-	 * Deletes the execution.
-	 */
-	void delete() throws RemoteException;
-
-	/**
-	 * Starts the execution.
-	 */
-	void start() throws RemoteException;
-
-	/**
-	 * Pauses the execution.
-	 */
-	void pause() throws RemoteException;
-
-	/**
-	 * Resumes a paused execution.
-	 */
-	void resume() throws RemoteException;
-
-	/**
-	 * Cancels the execution.
-	 */
-	void cancel() throws RemoteException;
-
-	@XmlType(name = "Report", propOrder = { "state", "created", "started",
-			"completed", "failed", "cancelled", "paused", "resumed" })
-	@XmlSeeAlso({ WorkflowReportDocument.class, ProcessorReportDocument.class,
-			ActivityReportDocument.class })
-	@XmlAccessorType(NONE)
-	public static abstract class ReportDocument {
-		@XmlAttribute
-		public String subject;
-		@XmlElement
-		public String state;
-		@XmlElement(required = true)
-		@XmlSchemaType(name = "dateTime")
-		public XMLGregorianCalendar created;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public XMLGregorianCalendar started;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public XMLGregorianCalendar completed;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public XMLGregorianCalendar failed;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public XMLGregorianCalendar cancelled;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public List<XMLGregorianCalendar> paused;
-		@XmlElement
-		@XmlSchemaType(name = "dateTime")
-		public List<XMLGregorianCalendar> resumed;
-	}
-
-	@XmlType(name = "WorkflowReport", propOrder = { "processor", "inputs",
-			"outputs" })
-	@XmlRootElement(name = "workflowReport")
-	@XmlAccessorType(NONE)
-	public static class WorkflowReportDocument extends ReportDocument {
-		@XmlElement(name = "processor")
-		public ArrayList<ProcessorReportDocument> processor = new ArrayList<ProcessorReportDocument>();
-		@XmlElement(name = "input")
-		public ArrayList<PortMapping> inputs = new ArrayList<PortMapping>();
-		@XmlElement(name = "output")
-		public ArrayList<PortMapping> outputs = new ArrayList<PortMapping>();
-	}
-
-	@XmlType(name = "ProcessorReport", propOrder = { "jobsQueued",
-			"jobsStarted", "jobsCompleted", "jobsErrored", "properties",
-			"activity" })
-	@XmlAccessorType(NONE)
-	public static class ProcessorReportDocument extends ReportDocument {
-		@XmlElement(name = "jobsQueued", required = true)
-		public int jobsQueued;
-		@XmlElement(name = "jobsStarted", required = true)
-		public int jobsStarted;
-		@XmlElement(name = "jobsCompleted", required = true)
-		public int jobsCompleted;
-		@XmlElement(name = "jobsErrored", required = true)
-		public int jobsErrored;
-		@XmlElement(name = "property")
-		@XmlElementWrapper(name = "properties")
-		public ArrayList<Property> properties = new ArrayList<Property>();
-		@XmlElement(name = "activity")
-		public ArrayList<ActivityReportDocument> activity = new ArrayList<ActivityReportDocument>();
-
-		@XmlType(name = "ProcessorProperty")
-		@XmlAccessorType(NONE)
-		public static class Property {
-			@XmlAttribute(name = "key", required = true)
-			String key;
-			@XmlValue
-			String value;
-
-			public Property() {
-			}
-
-			public String getKey() {
-				return key;
-			}
-
-			public String getValue() {
-				return value;
-			}
-
-			Property(String key, String value) {
-				this.key = key;
-				this.value = value;
-			}
-		}
-	}
-
-	@XmlType(name = "ActivityReport", propOrder = { "workflow", "inputs",
-			"outputs" })
-	@XmlAccessorType(NONE)
-	public static class ActivityReportDocument extends ReportDocument {
-		@XmlElement(name = "workflow")
-		public ArrayList<WorkflowReportDocument> workflow = new ArrayList<WorkflowReportDocument>();
-		@XmlElement(name = "input")
-		public ArrayList<PortMapping> inputs = new ArrayList<PortMapping>();
-		@XmlElement(name = "output")
-		public ArrayList<PortMapping> outputs = new ArrayList<PortMapping>();
-	}
-
-	@XmlType(name = "PortMapping")
-	@XmlAccessorType(NONE)
-	public static class PortMapping {
-		public PortMapping() {
-		}
-
-		PortMapping(String port, URI data) {
-			this.name = port;
-			this.reference = data;
-		}
-
-		@XmlAttribute(name = "name")
-		public String name;
-		@XmlAttribute(name = "ref")
-		@XmlSchemaType(name = "anyURI")
-		public URI reference;
-	}
-}


[35/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java b/server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
deleted file mode 100644
index e175bf8..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Roles.USER;
-
-import java.net.URI;
-import java.util.Date;
-import java.util.List;
-
-import javax.annotation.security.RolesAllowed;
-import javax.jws.WebMethod;
-import javax.jws.WebParam;
-import javax.jws.WebResult;
-import javax.jws.WebService;
-import javax.xml.bind.annotation.XmlElement;
-
-import org.apache.cxf.annotations.WSDLDocumentation;
-import org.ogf.usage.JobUsageRecord;
-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.UnknownRunException;
-import org.taverna.server.master.rest.TavernaServerREST;
-import org.taverna.server.port_description.OutputDescription;
-
-/**
- * The SOAP service interface to Taverna 3 Server.
- * 
- * @author Donal Fellows
- * @see TavernaServerREST
- */
-@RolesAllowed(USER)
-@WebService(name = "tavernaService", targetNamespace = SERVER_SOAP)
-@WSDLDocumentation("The SOAP service interface to Taverna " + Version.JAVA
-		+ " Server.")
-public interface TavernaServerSOAP {
-	/**
-	 * Make a run for a particular workflow.
-	 * 
-	 * @param workflow
-	 *            The workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow.")
-	RunReference submitWorkflow(
-			@WebParam(name = "workflow") @XmlElement(required = true) Workflow workflow)
-					throws NoUpdateException, NoCreateException;
-
-	/**
-	 * Make a run for a particular workflow.
-	 * 
-	 * @param workflow
-	 *            The workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow.")
-	RunReference submitWorkflowMTOM(
-			@WebParam(name = "workflow") @XmlElement(required = true) WrappedWorkflow workflow)
-			throws NoUpdateException;
-
-	/**
-	 * Make a run for a particular workflow, where that workflow will be
-	 * downloaded from elsewhere. The URI <i>must</i> be publicly readable.
-	 * 
-	 * @param workflowURI
-	 *            The URI to the workflow to instantiate.
-	 * @return Annotated handle for created run.
-	 * @throws NoUpdateException
-	 * @throws NoCreateException
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Make a run for a particular workflow where that "
-			+ "workflow is given by publicly readable URI.")
-	RunReference submitWorkflowByURI(
-			@WebParam(name = "workflowURI") @XmlElement(required = true) URI workflowURI)
-			throws NoCreateException, NoUpdateException;
-
-	/**
-	 * Get the list of existing runs owned by the user.
-	 * 
-	 * @return Annotated handle list.
-	 */
-	@WebResult(name = "Run")
-	@WSDLDocumentation("Get the list of existing runs owned by the user.")
-	RunReference[] listRuns();
-
-	/**
-	 * Get the upper limit on the number of runs that the user may create at
-	 * once.
-	 * 
-	 * @return The limit. <b>NB:</b> the number currently operating may be
-	 *         larger, but in that case no further runs can be made until some
-	 *         of the old ones are destroyed.
-	 */
-	@WebResult(name = "MaxSimultaneousRuns")
-	@WSDLDocumentation("Get the upper limit on the number of runs that the user may create at once.")
-	int getServerMaxRuns();
-
-	/**
-	 * Get the list of allowed workflows. If the list is empty, <i>any</i>
-	 * workflow may be used.
-	 * 
-	 * @return A list of workflow documents.
-	 */
-	@WebMethod(operationName = "getPermittedWorkflowURIs")
-	@WebResult(name = "PermittedWorkflowURI")
-	@WSDLDocumentation("Get the list of URIs to allowed workflows. If the list is empty, any workflow may be used including those not submitted via URI.")
-	URI[] getServerWorkflows();
-
-	/**
-	 * Get the list of allowed event listeners.
-	 * 
-	 * @return A list of listener names.
-	 */
-	@WebMethod(operationName = "getPermittedListenerTypes")
-	@WebResult(name = "PermittedListenerType")
-	@WSDLDocumentation("Get the list of allowed types of event listeners.")
-	String[] getServerListeners();
-
-	/**
-	 * Get the list of notification fabrics.
-	 * 
-	 * @return A list of listener names.
-	 */
-	@WebMethod(operationName = "getEnabledNotificationFabrics")
-	@WebResult(name = "EnabledNotifierFabric")
-	@WSDLDocumentation("Get the list of notification fabrics. Each is a URI scheme.")
-	String[] getServerNotifiers();
-
-	@WebMethod(operationName = "getCapabilities")
-	@WebResult(name = "Capabilities")
-	@WSDLDocumentation("Get the workflow execution capabilities of this "
-			+ "Taverna Server instance.")
-	List<Capability> getServerCapabilities();
-
-	/**
-	 * Destroy a run immediately. This might or might not actually relinquish
-	 * resources; that's up to the service implementation and deployment.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the lifetime of the
-	 *             run.
-	 */
-	@WSDLDocumentation("Destroy a run immediately.")
-	void destroyRun(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the workflow document used to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The workflow document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationWorkflow")
-	@WSDLDocumentation("Get the workflow document used to create the given run.")
-	Workflow getRunWorkflow(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the workflow document used to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The workflow document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationWorkflow")
-	@WSDLDocumentation("Get the workflow document used to create the given run.")
-	WrappedWorkflow getRunWorkflowMTOM(
-			@WebParam(name = "runName") String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get a description of the profiles supported by the workflow document used
-	 * to create the given run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return A description of the supported profiles.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Profiles")
-	@WSDLDocumentation("Get a description of the profiles supported by the workflow document used to create the given run.")
-	ProfileList getRunWorkflowProfiles(
-			@WebParam(name = "runName") String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the descriptive name of the workflow run. The descriptive name
-	 * carries no deep information.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The descriptive name of the run.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "DescriptiveName")
-	@WSDLDocumentation("Get the descriptive name of the workflow run. Carries no deep information.")
-	String getRunDescriptiveName(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the descriptive name of the workflow run. The descriptive name
-	 * carries no deep information.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param descriptiveName
-	 *            The new descriptive name to set. Note that the implementation
-	 *            is allowed to arbitrarily truncate this value.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not permitted to update this run.
-	 */
-	@WSDLDocumentation("Set the descriptive name of the workflow run. Carries no deep information.")
-	void setRunDescriptiveName(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "descriptiveName") @XmlElement(required = true) String descriptiveName)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the description of the inputs to the workflow run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The input description
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "RunInputDescription")
-	@WSDLDocumentation("Get the description of the inputs currently set up for the given workflow run.")
-	InputDescription getRunInputs(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get a description of what inputs the workflow run <i>expects</i> to
-	 * receive.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The description document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "RunInputDescriptor")
-	@WSDLDocumentation("Get a description of what inputs the given workflow run expects to receive.")
-	org.taverna.server.port_description.InputDescription getRunInputDescriptor(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Tells the run to use the given Baclava file for all inputs.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param fileName
-	 *            The name of the file to use. Must not start with a <tt>/</tt>
-	 *            or contain a <tt>..</tt> element.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state
-	 */
-	@WSDLDocumentation("Tells the given run to use the given already-uploaded Baclava file for all inputs.")
-	void setRunInputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "baclavaFileName") String fileName)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * Tells the run to use the given file for input on the given port. This
-	 * overrides any previously set file or value on the port and causes the
-	 * server to forget about using a Baclava file for all inputs.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to use the file for.
-	 * @param portFilename
-	 *            The file to use on the port. Must not start with a <tt>/</tt>
-	 *            or contain a <tt>..</tt> element.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the input port may not be changed to the contents of the
-	 *             given file.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given file for input on the given port.")
-	void setRunInputPortFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "portFileName") @XmlElement(required = true) String portFilename)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException,
-			BadPropertyValueException;
-
-	/**
-	 * Tells the run to use the given value for input on the given port. This
-	 * overrides any previously set file or value on the port and causes the
-	 * server to forget about using a Baclava file for all inputs. Note that
-	 * this is wholly unsuitable for use with binary data.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to use the file for.
-	 * @param portValue
-	 *            The literal value to use on the port.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the input port may not be changed to the given literal
-	 *             value.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given literal string value for input on the given port.")
-	void setRunInputPortValue(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "portValue") @XmlElement(required = true) String portValue)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException, BadPropertyValueException;
-
-	/**
-	 * Tells the given run to use the given list delimiter (a single-character
-	 * string value) for splitting the input on the given port. Note that
-	 * nullability of the delimiter is supported here.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param portName
-	 *            The port to set the list delimiter for.
-	 * @param delimiter
-	 *            The single-character value (in range U+00001..U+0007F) to use
-	 *            as the delimiter, or <tt>null</tt> for no delimiter at all.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state.
-	 * @throws BadPropertyValueException
-	 *             If the delimiter may not be changed to the given literal
-	 *             value.
-	 */
-	@WSDLDocumentation("Tells the given run to use the given list delimiter (a single-character string value) for splitting the input on the given port. Note that nullability of the delimiter is supported here.")
-	void setRunInputPortListDelimiter(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "portName") @XmlElement(required = true) String portName,
-			@WebParam(name = "delimiter") String delimiter)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException, BadPropertyValueException;
-
-	/**
-	 * Get the Baclava file where the output of the run will be written.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The filename, or <tt>null</tt> if the results will be written to
-	 *         a subdirectory <tt>out</tt> of the run's working directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "OutputBaclavaFile")
-	@WSDLDocumentation("Get the Baclava file where the output of the run will be written.")
-	String getRunOutputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the Baclava file where the output of the run will be written.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param outputFile
-	 *            The filename for the Baclava file, or <tt>null</tt> or the
-	 *            empty string to indicate that the results are to be written to
-	 *            the subdirectory <tt>out</tt> of the run's working directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws FilesystemAccessException
-	 *             If the filename is illegal (starts with a <tt>/</tt> or
-	 *             contains a <tt>..</tt> element.
-	 * @throws BadStateChangeException
-	 *             If the run is not in the {@link Status#Initialized
-	 *             Initialized} state
-	 */
-	@WSDLDocumentation("Set the Baclava file where the output of the run will be written.")
-	void setRunOutputBaclavaFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "baclavaFileName") String outputFile)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, BadStateChangeException;
-
-	/**
-	 * Return a description of the outputs of a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Description document (higher level than filesystem traverse).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws BadStateChangeException
-	 *             If the run is in the {@link Status#Initialized Initialized}
-	 *             state
-	 * @throws FilesystemAccessException
-	 *             If there is an exception when accessing the filesystem.
-	 * @throws NoDirectoryEntryException
-	 *             If things are odd in the filesystem.
-	 */
-	@WebResult(name = "OutputDescription")
-	@WSDLDocumentation("Return a description of the outputs of a run. Only known during/after the run.")
-	OutputDescription getRunOutputDescription(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, BadStateChangeException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the time when the run will be eligible to be automatically deleted.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return A date at which the expiry will be scheduled. The actual deletion
-	 *         will happen an arbitrary amount of time later (depending on
-	 *         system policy).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Expiry")
-	@WSDLDocumentation("Get the time when the run will be eligible to be automatically deleted.")
-	Date getRunExpiry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set when the run will be eligible to be automatically deleted.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param expiry
-	 *            A date at which the expiry will be scheduled. The actual
-	 *            deletion will happen an arbitrary amount of time later
-	 *            (depending on system policy).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the lifetime of the
-	 *             run.
-	 */
-	@WSDLDocumentation("Set when the run will be eligible to be automatically deleted.")
-	void setRunExpiry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "expiry") @XmlElement(required = true) Date expiry)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the time when the run was created.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was created (modulo some internal
-	 *         overhead).
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "CreationTime")
-	@WSDLDocumentation("Get the time when the run was created.")
-	Date getRunCreationTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the time when the run was started.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was started (modulo some internal
-	 *         overhead) or <tt>null</tt> to indicate that it has never started.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StartTime")
-	@WSDLDocumentation("Get the time when the run was started.")
-	Date getRunStartTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the time when the run was detected as having finished.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The moment when the run was believed stopped. Note that this may
-	 *         not be when the run <i>actually</i> finished; promptness of
-	 *         detection depends on many factors.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "FinishTime")
-	@WSDLDocumentation("Get the time when the run was detected as having finished.")
-	Date getRunFinishTime(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the current status of the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The status code.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Status")
-	@WSDLDocumentation("Get the current status of the given workflow run.")
-	Status getRunStatus(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Set the status of a run. This is used to start it executing, make it stop
-	 * executing, etc. Note that changing the status of a run can <i>never</i>
-	 * cause the run to be destroyed.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param status
-	 *            The status to change to. Changing to the current status will
-	 *            always have no effect.
-	 * @return An empty string if the state change was completed, or a
-	 *         description (never empty) of why the state change is ongoing.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws BadStateChangeException
-	 *             If the state change requested is impossible.
-	 */
-	@WebResult(name = "PartialityReason")
-	@WSDLDocumentation("Set the status of a given workflow run.")
-	String setRunStatus(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "status") @XmlElement(required = true) Status status)
-			throws UnknownRunException, NoUpdateException,
-			BadStateChangeException;
-
-	/**
-	 * Get the names of the event listeners attached to the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The listener names.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "ListenerName")
-	@WSDLDocumentation("Get the names of the event listeners attached to the run.")
-	String[] getRunListeners(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Adds an event listener to the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerType
-	 *            The type of event listener to add. Must be one of the names
-	 *            returned by the {@link #getServerListeners()} operation.
-	 * @param configuration
-	 *            The configuration document for the event listener; the
-	 *            interpretation of the configuration is up to the listener.
-	 * @return The actual name of the listener.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user isn't allowed to manipulate the run.
-	 * @throws NoListenerException
-	 *             If the listener construction fails (<i>e.g.</i>, due to an
-	 *             unsupported <b>listenerType</b> or a problem with the
-	 *             <b>configuration</b>).
-	 */
-	@WebResult(name = "ListenerName")
-	@WSDLDocumentation("Adds an event listener to the run.")
-	String addRunListener(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerType") @XmlElement(required = true) String listenerType,
-			@WebParam(name = "configuration") @XmlElement(required = true) String configuration)
-			throws UnknownRunException, NoUpdateException, NoListenerException;
-
-	/**
-	 * Returns the standard output of the workflow run. Unstarted runs return
-	 * the empty string.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/stdout).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine printed on its stdout.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StandardOutput")
-	@WSDLDocumentation("Returns the stdout from the run engine.")
-	String getRunStdout(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the standard error of the workflow run. Unstarted runs return the
-	 * empty string.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/stderr).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine printed on its stderr.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "StandardError")
-	@WSDLDocumentation("Returns the stderr from the run engine.")
-	String getRunStderr(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the usage record for the workflow run. Unfinished runs return
-	 * <tt>null</tt>.
-	 * <p>
-	 * The equivalent thing can also be fetched from the relevant listener
-	 * property (i.e., io/usage).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The usage record, or <tt>null</tt>.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "ResourceUsage")
-	@WSDLDocumentation("Returns the resource usage from the run engine.")
-	JobUsageRecord getRunUsageRecord(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the log of the workflow run. Unstarted runs return the empty
-	 * string.
-	 * <p>
-	 * This can also be fetched from the appropriate file (i.e.,
-	 * <tt>logs/detail.log</tt>).
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whatever the run engine wrote to its log.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Log")
-	@WSDLDocumentation("Returns the detailed log from the run engine.")
-	String getRunLog(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Returns the run bundle of a run. The run must be <i>finished</i> for this
-	 * to be guaranteed to be present, and must <i>not</i> have had its output
-	 * generated as Baclava.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The contents of the run bundle.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If there was a problem reading the bundle.
-	 * @throws NoDirectoryEntryException
-	 *             If the bundle doesn't exist currently.
-	 */
-	@WebResult(name = "RunBundle")
-	@WSDLDocumentation("Gets the run bundle of a finished run. MTOM support recommended!")
-	FileContents getRunBundle(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Gets whether to generate provenance (in a run bundle) for a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return Whether provenance will be generated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "GenerateProvenance")
-	@WSDLDocumentation("Gets whether a run generates provenance.")
-	boolean getRunGenerateProvenance(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Sets whether to generate provenance (in a run bundle) for a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param generateProvenance
-	 *            Whether to generate provenance.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to manipulate the run.
-	 */
-	@WSDLDocumentation("Sets whether a run generates provenance. "
-			+ "Only usefully settable before the run is started.")
-	void setRunGenerateProvenance(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "generateProvenance") @XmlElement(required = true) boolean generateProvenance)
-			throws UnknownRunException, NoUpdateException;
-
-	/**
-	 * Get the owner of the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The status code.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 */
-	@WebResult(name = "Owner")
-	@WSDLDocumentation("Get the owner of the given workflow run.")
-	String getRunOwner(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException;
-
-	/**
-	 * Get the list of permissions associated with a workflow run.
-	 * 
-	 * @param runName
-	 *            The name of the run whose permissions are to be obtained.
-	 * @return A description of the non-<tt>none</tt> permissions.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the current
-	 *             user is not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If asked to provide this information about a run that the
-	 *             current user may see but where they are not the owner of it.
-	 */
-	@WebResult(name = "PermissionList")
-	@WSDLDocumentation("Get the list of permissions associated with a given workflow run.")
-	PermissionList listRunPermissions(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set the permission for a user to access and update a particular workflow
-	 * run.
-	 * 
-	 * @param runName
-	 *            The name of the run whose permissions are to be updated.
-	 * @param userName
-	 *            The name of the user about whom this call is talking.
-	 * @param permission
-	 *            The permission level to set.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the current
-	 *             user is not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If asked to provide this information about a run that the
-	 *             current user may see but where they are not the owner of it.
-	 */
-	@WSDLDocumentation("Set the permission for a user to access and update a given workflow run.")
-	void setRunPermission(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "userName") @XmlElement(required = true) String userName,
-			@WebParam(name = "permission") @XmlElement(required = true) Permission permission)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Get the credentials associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The collection of credentials.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may see the credentials.
-	 */
-	@WebResult(name = "Credentials")
-	@WSDLDocumentation("Get the credentials (passwords, private keys) associated with the given workflow run. Only the owner may do this.")
-	Credential[] getRunCredentials(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set a credential associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param credentialID
-	 *            The handle of the credential to set. If empty, a new
-	 *            credential will be created.
-	 * @param credential
-	 *            The credential to set.
-	 * @return The handle of the credential that was created or updated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the credentials.
-	 * @throws InvalidCredentialException
-	 *             If the <b>credential</b> fails its checks.
-	 * @throws NoCredentialException
-	 *             If the <b>credentialID</b> is not empty but does not
-	 *             correspond to an existing credential.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WebResult(name = "credentialID")
-	@WSDLDocumentation("Set a credential (password, private key, etc.) associated with the given run. Only the owner may do this.")
-	String setRunCredential(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID,
-			@WebParam(name = "credential") @XmlElement(required = true) Credential credential)
-			throws UnknownRunException, NotOwnerException,
-			InvalidCredentialException, NoCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Delete a credential associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param credentialID
-	 *            The handle of the credential to delete. If empty, a new
-	 *            credential will be created.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the credentials.
-	 * @throws NoCredentialException
-	 *             If the given credentialID does not exist.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WSDLDocumentation("Delete a credential associated with the given run. Only the owner may do this.")
-	void deleteRunCredential(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException;
-
-	/**
-	 * Get the certificate collections associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @return The collection of credentials.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may see the credentials.
-	 */
-	@WebResult(name = "CertificateCollections")
-	@WSDLDocumentation("Get the trusted (server or CA) certificates associated with the run. Only the owner may do this.")
-	Trust[] getRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName)
-			throws UnknownRunException, NotOwnerException;
-
-	/**
-	 * Set a certificate collection associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param certificateID
-	 *            The handle of the certificate collection to set. If empty, a
-	 *            new certificate collection will be created.
-	 * @param certificate
-	 *            The certificate collection to set.
-	 * @return The handle of the certificate set that was created or updated.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the certificates.
-	 * @throws InvalidCredentialException
-	 *             If the <b>certificate</b> fails its checks.
-	 * @throws NoCredentialException
-	 *             If the <b>credentialID</b> is not empty but does not
-	 *             correspond to an existing certificate collection.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WebResult(name = "certificateID")
-	@WSDLDocumentation("Set a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
-	String setRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "certificateID") String certificateID,
-			@WebParam(name = "certificate") @XmlElement(required = true) Trust certificate)
-			throws UnknownRunException, NotOwnerException,
-			InvalidCredentialException, NoCredentialException,
-			BadStateChangeException;
-
-	/**
-	 * Delete a certificate collection associated with the run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param certificateID
-	 *            The handle of the credential to delete.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NotOwnerException
-	 *             If the user is permitted to see the run, but isn't the owner;
-	 *             only the owner may manipulate the certificates.
-	 * @throws NoCredentialException
-	 *             If the given certificateID does not exist.
-	 * @throws BadStateChangeException
-	 *             If an attempt to manipulate the credentials is done after the
-	 *             workflow has started running.
-	 */
-	@WSDLDocumentation("Delete a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
-	void deleteRunCertificates(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "certificateID") @XmlElement(required = true) String certificateID)
-			throws UnknownRunException, NotOwnerException,
-			NoCredentialException, BadStateChangeException;
-
-	/**
-	 * Get the contents of any directory at/under the run's working directory.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return A list of entries. They are assumed to be all directories or
-	 *         files.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "DirectoryEntry")
-	@WSDLDocumentation("Get the contents of any directory at/under the run's working directory.")
-	DirEntry[] getRunDirectoryContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of any directory (and its subdirectories) at/under the
-	 * run's working directory, returning it as a compressed ZIP file. Runs do
-	 * not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return A serialized ZIP file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "ZipFile")
-	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file.")
-	byte[] getRunDirectoryAsZip(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of any directory (and its subdirectories) at/under the
-	 * run's working directory, returning it as a compressed ZIP file that is
-	 * streamed via MTOM. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param directory
-	 *            The name of the directory to fetch; the main working directory
-	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return An MTOM-streamable ZIP file reference.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a file).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the directory can't be looked up.
-	 */
-	@WebResult(name = "ZipStream")
-	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file that is streamed by MTOM.")
-	ZippedDirectory getRunDirectoryAsZipMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Make a new empty directory beneath an existing one, which must be the
-	 * run's working directory or a directory beneath it. Runs do not share
-	 * working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param parent
-	 *            The parent directory that will have the new directory added
-	 *            beneath it.
-	 * @param name
-	 *            The name of the directory to create. Must not be the same as
-	 *            any other file or directory in the <i>parent</i> directory.
-	 *            The name <i>must not</i> consist of <tt>..</tt> or have a
-	 *            <tt>/</tt> in it.
-	 * @return A reference to the created directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., making something with
-	 *             the same name as something that already exists).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 */
-	@WebResult(name = "CreatedDirectory")
-	@WSDLDocumentation("Make a new empty directory beneath an existing one, all relative to the given run's main working directory.")
-	DirEntry makeRunDirectory(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
-			@WebParam(name = "directoryName") @XmlElement(required = true) String name)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Make a new empty file in an existing directory, which may be the run's
-	 * working directory or any directory beneath it. Runs do not share working
-	 * directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param parent
-	 *            The parent directory that will have the new file added to it.
-	 * @param name
-	 *            The name of the file to create. Must not be the same as any
-	 *            other file or directory in the <i>parent</i> directory. The
-	 *            name <i>must not</i> consist of <tt>..</tt> or have a
-	 *            <tt>/</tt> in it.
-	 * @return A reference to the created file. The file will be empty.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., making something with
-	 *             the same name as something that already exists).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the containing directory can't be looked up.
-	 */
-	@WebResult(name = "CreatedFile")
-	@WSDLDocumentation("Make a new empty file in an existing directory, which may be the run's working directory or any directory beneath it.")
-	DirEntry makeRunFile(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
-			@WebParam(name = "fileNameTail") @XmlElement(required = true) String name)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Destroy an entry (file or directory) in or beneath a run's working
-	 * directory. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param dirEntry
-	 *            Reference to an existing item in a directory that will be
-	 *            destroyed. May be a reference to either a file or a directory.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., deleting something
-	 *             which doesn't exist or attempting to delete the main working
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the name of the file or directory can't be looked up.
-	 */
-	@WSDLDocumentation("Destroy an entry (file or directory) in or beneath a run's working directory.")
-	void destroyRunDirectoryEntry(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "directoryEntry") @XmlElement(required = true) DirEntry dirEntry)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to fetch; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The literal byte contents of the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContents")
-	@WSDLDocumentation("Get the contents of a file under the run's working directory.")
-	byte[] getRunFileContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the contents of a file under the run's working directory via MTOM.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to fetch; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The contents, described for transfer via MTOM.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContentsMTOM")
-	@WSDLDocumentation("Get the contents of a file via MTOM.")
-	FileContents getRunFileContentsMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to update; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @param newContents
-	 *            The literal bytes to set the file contents to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
-	void setRunFileContents(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file,
-			@WebParam(name = "contents") @XmlElement(required = true) byte[] newContents)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory. Runs do not
-	 * share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param newContents
-	 *            The description of what file to set, and what to the file
-	 *            contents should be set to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
-	void setRunFileContentsMTOM(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "contents") @XmlElement(required = true) FileContents newContents)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Set the contents of a file under the run's working directory to the
-	 * contents of a publicly readable URI. Runs do not share working
-	 * directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to update; the main working directory is
-	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @param reference
-	 *            The publicly readable URI whose contents are to become the
-	 *            literal bytes of the file's contents.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., writing the contents of
-	 *             a directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WSDLDocumentation("Set the contents of a file under the run's working directory from the contents of a publicly readable URI.")
-	void setRunFileContentsFromURI(@WebParam(name = "runName") String runName,
-			@WebParam(name = "fileName") DirEntryReference file,
-			@WebParam(name = "contents") URI reference)
-			throws UnknownRunException, NoUpdateException,
-			FilesystemAccessException, NoDirectoryEntryException;
-
-	/**
-	 * Get the length of any file (in bytes) at/under the run's working
-	 * directory. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the length of; the main working
-	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The number of bytes in the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the length of a
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileLength")
-	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
-	long getRunFileLength(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the time that the file or directory (at/under the run's working
-	 * directory) was last modified. Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the modification date of; the main
-	 *            working directory is <tt>/</tt> and <tt>..</tt> is always
-	 *            disallowed.
-	 * @return The modification date of the file or directory, as understood by
-	 *         the underlying operating system.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated.
-	 * @throws NoDirectoryEntryException
-	 *             If the file or directory doesn't exist.
-	 */
-	@WebResult(name = "FileModified")
-	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
-	Date getRunFileModified(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the content type of any file at/under the run's working directory.
-	 * Runs do not share working directories.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param file
-	 *            The name of the file to get the length of; the main working
-	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
-	 * @return The content type of the file.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws FilesystemAccessException
-	 *             If some assumption is violated (e.g., reading the length of a
-	 *             directory).
-	 * @throws NoDirectoryEntryException
-	 *             If the file doesn't exist.
-	 */
-	@WebResult(name = "FileContentType")
-	@WSDLDocumentation("Get the content type of any file at/under the run's working directory.")
-	String getRunFileType(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
-			throws UnknownRunException, FilesystemAccessException,
-			NoDirectoryEntryException;
-
-	/**
-	 * Get the configuration document for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @return The configuration document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists.
-	 */
-	@WebResult(name = "ListenerConfiguration")
-	@WSDLDocumentation("Get the configuration document for an event listener attached to a run.")
-	String getRunListenerConfiguration(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Get the list of properties supported by an event listener attached to a
-	 * run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @return The list of property names.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists.
-	 */
-	@WebResult(name = "ListenerPropertyName")
-	@WSDLDocumentation("Get the list of properties supported by an event listener attached to a run.")
-	String[] getRunListenerProperties(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Get the value of a property for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @param propertyName
-	 *            The name of the property to read.
-	 * @return The configuration document.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists or if the listener has no such
-	 *             property.
-	 */
-	@WebResult(name = "ListenerPropertyValue")
-	@WSDLDocumentation("Get the value of a property for an event listener attached to a run.")
-	String getRunListenerProperty(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
-			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName)
-			throws UnknownRunException, NoListenerException;
-
-	/**
-	 * Set the value of a property for an event listener attached to a run.
-	 * 
-	 * @param runName
-	 *            The handle of the run.
-	 * @param listenerName
-	 *            The name of the listener attached.
-	 * @param propertyName
-	 *            The name of the property to write.
-	 * @param value
-	 *            The value to set the property to.
-	 * @throws UnknownRunException
-	 *             If the server doesn't know about the run or if the user is
-	 *             not permitted to see it.
-	 * @throws NoListenerException
-	 *             If no such listener exists, the listener has no such
-	 *             property, or the value is considered "unacceptable" in some
-	 *             way.
-	 * @throws NoUpdateException
-	 *             If the user is not allowed to make modifications to the run.
-	 */
-	@WSDLDocumentation("Set the value of a property for an event listener attached to a run.")
-	void setRunListenerProperty(
-			@WebParam(name = "runName") @XmlElement(required = true) String runName,
-			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
-			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName,
-			@WebParam(name = "propertyValue") @XmlElement(required = true) String value)
-			throws UnknownRunException, NoUpdateException, NoListenerException;
-
-	/**
-	 * Gets the status of the server. Follows the HELIO Monitoring Service
-	 * protocol.
-	 * 
-	 * @return A status string.
-	 */
-	@WSDLDocumentation("A simple way to get the status of the overall server.")
-	@WebResult(name = "ServerStatus")
-	String getServerStatus();
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java b/server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
deleted file mode 100644
index cd06115..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE.txt" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import static javax.xml.bind.annotation.XmlAccessType.NONE;
-import static org.apache.commons.io.IOUtils.closeQuietly;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.Workflow;
-
-import uk.org.taverna.scufl2.api.io.ReaderException;
-import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
-import uk.org.taverna.scufl2.api.io.WriterException;
-
-/**
- * An MTOM-capable description of how to transfer the contents of a file.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "WorkflowReference")
-@XmlAccessorType(NONE)
-public class WrappedWorkflow {
-	@XmlMimeType("application/octet-stream")
-	// JAXB bug: must be this
-	public DataHandler workflowData;
-	Workflow workflow;
-
-	/**
-	 * Initialize the contents of this descriptor from the given file and
-	 * content type.
-	 * 
-	 * @param workflow
-	 *            The workflow that is to be reported.
-	 */
-	public void setWorkflow(Workflow workflow) {
-		workflowData = new DataHandler(new WorkflowSource(workflow));
-	}
-
-	@XmlTransient
-	public Workflow getWorkflow() throws IOException {
-		if (workflow != null)
-			return workflow;
-		try {
-			return new Workflow(new WorkflowBundleIO().readBundle(
-					workflowData.getInputStream(), null));
-		} catch (ReaderException e) {
-			throw new IOException("problem converting to scufl2 bundle", e);
-		}
-	}
-}
-
-/**
- * A data source that knows how to deliver a workflow.
- * 
- * @author Donal Fellows
- */
-class WorkflowSource implements DataSource {
-	WorkflowSource(Workflow workflow) {
-		this.wf = workflow;
-		this.io = new WorkflowBundleIO();
-	}
-
-	Workflow wf;
-	final WorkflowBundleIO io;
-
-	@Override
-	public String getContentType() {
-		return wf.getPreferredContentType().getContentType();
-	}
-
-	@Override
-	public String getName() {
-		switch (wf.getPreferredContentType()) {
-		case SCUFL2:
-			return "workflow.scufl2";
-		case T2FLOW:
-			return "workflow.t2flow";
-		default:
-			return "workflow";
-		}
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		PipedInputStream is = new PipedInputStream();
-		final OutputStream os = new PipedOutputStream(is);
-		new Worker() {
-			@Override
-			public void doWork() throws WriterException, IOException {
-				io.writeBundle(wf.getScufl2Workflow(), os, wf
-						.getPreferredContentType().getContentType());
-			}
-
-			@Override
-			public void doneWork() {
-				closeQuietly(os);
-			}
-		};
-		return is;
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		final PipedInputStream is = new PipedInputStream();
-		OutputStream os = new PipedOutputStream(is);
-		new Worker() {
-			@Override
-			public void doWork() throws IOException, ReaderException {
-				wf = new Workflow(io.readBundle(is, null));
-			}
-
-			@Override
-			public void doneWork() {
-				closeQuietly(is);
-			}
-		};
-		return os;
-	}
-
-	static abstract class Worker extends Thread {
-		public Worker() {
-			setDaemon(true);
-			start();
-		}
-
-		public abstract void doWork() throws Exception;
-
-		public abstract void doneWork();
-
-		@Override
-		public void run() {
-			try {
-				doWork();
-			} catch (Exception e) {
-				// do nothing.
-			} finally {
-				doneWork();
-			}
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java b/server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
deleted file mode 100644
index 90fe51b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.activation.UnsupportedDataTypeException;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.Directory;
-
-/**
- * An MTOM-capable description of how to transfer the zipped contents of a
- * directory.
- * 
- * @author Donal Fellows
- * @see Directory#getContentsAsZip()
- */
-@XmlType(name = "ZippedDirectory")
-public class ZippedDirectory {
-	@XmlElement
-	public String name;
-	@XmlMimeType("application/octet-stream")
-	// JAXB bug: must be this
-	public DataHandler fileData;
-
-	public ZippedDirectory() {
-	}
-
-	/**
-	 * Initialise the contents of this descriptor from the given directory.
-	 * 
-	 * @param dir
-	 *            The directory that is to be reported.
-	 */
-	public ZippedDirectory(Directory dir) {
-		name = dir.getFullName();
-		fileData = new DataHandler(new ZipSource(dir));
-	}
-}
-
-/**
- * A data source that knows how to communicate with the Taverna Server back-end.
- * 
- * @author Donal Fellows
- */
-class ZipSource implements DataSource {
-	ZipSource(Directory d) {
-		this.d = d;
-	}
-
-	private final Directory d;
-
-	@Override
-	public String getContentType() {
-		return APPLICATION_ZIP_TYPE.toString();
-	}
-
-	@Override
-	public String getName() {
-		return d.getName();
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		try {
-			return d.getContentsAsZip();
-		} catch (FilesystemAccessException e) {
-			throw new IOException(e);
-		}
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		throw new UnsupportedDataTypeException();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
deleted file mode 100644
index 51d9b69..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the SOAP interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_SOAP, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.soap;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java b/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
deleted file mode 100644
index 487dbd0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.usage;
-
-import java.util.Date;
-
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Index;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-import javax.xml.bind.JAXBException;
-
-import org.ogf.usage.JobUsageRecord;
-
-/**
- * A usage record as recorded in the database.
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(table = "USAGE_RECORD_LOG", schema = "UR", cacheable = "true")
-@Queries({ @Query(name = "allByDate", value = "SELECT USAGE_RECORD FROM UR.USAGE_RECORD_LOG ORDER BY CREATE_DATE", resultClass = String.class, unmodifiable = "true", unique = "false", language = "SQL") })
-public class UsageRecord {
-	/**
-	 * Create an empty usage record database entry.
-	 */
-	public UsageRecord() {
-	}
-
-	/**
-	 * Create a usage record database entry that is populated from the given UR.
-	 * 
-	 * @param usageRecord
-	 *            The originating usage record.
-	 * @throws JAXBException
-	 *             If deserialization of the record fails.
-	 */
-	public UsageRecord(String usageRecord) throws JAXBException {
-		JobUsageRecord jur = JobUsageRecord.unmarshal(usageRecord);
-		setUsageRecord(usageRecord);
-		setCreateDate(jur.getRecordIdentity().getCreateTime()
-				.toGregorianCalendar().getTime());
-		setId(jur.getRecordIdentity().getRecordId());
-		setUserid(jur.getUserIdentity().get(0).getLocalUserId());
-	}
-
-	/**
-	 * Create a usage record database entry that is populated from the given UR.
-	 * 
-	 * @param usageRecord
-	 *            The originating usage record.
-	 * @throws JAXBException
-	 *             If serialization of the record fails.
-	 */
-	public UsageRecord(JobUsageRecord usageRecord) throws JAXBException {
-		setUsageRecord(usageRecord.marshal());
-		setCreateDate(usageRecord.getRecordIdentity().getCreateTime()
-				.toGregorianCalendar().getTime());
-		setId(usageRecord.getRecordIdentity().getRecordId());
-		setUserid(usageRecord.getUserIdentity().get(0).getLocalUserId());
-	}
-
-	@PrimaryKey
-	@Column(name = "ID", length = 40)
-	private String id;
-
-	@Persistent
-	@Index(name = "USERID_IDX")
-	@Column(name = "USERID", length = 24)
-	private String userid;
-
-	@Persistent
-	@Index(name = "CREATE_IDX")
-	@Column(name = "CREATE_DATE")
-	private Date createDate;
-
-	@Persistent
-	@Column(name = "USAGE_RECORD", length = 32000)
-	// TODO Consider moving to BLOB (CLOB?) type
-	private String usageRecord;
-
-	public String getId() {
-		return id;
-	}
-
-	public void setId(String id) {
-		this.id = id;
-	}
-
-	public String getUserid() {
-		return userid;
-	}
-
-	public void setUserid(String userid) {
-		this.userid = userid;
-	}
-
-	public Date getCreateDate() {
-		return createDate;
-	}
-
-	public void setCreateDate(Date createDate) {
-		this.createDate = createDate;
-	}
-
-	public String getUsageRecord() {
-		return usageRecord;
-	}
-
-	public void setUsageRecord(String usageRecord) {
-		this.usageRecord = usageRecord;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java b/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
deleted file mode 100644
index 12de304..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.usage;
-
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.annotation.PreDestroy;
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.logging.Log;
-import org.ogf.usage.JobUsageRecord;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.api.ManagementModel;
-import org.taverna.server.master.utils.Contextualizer;
-import org.taverna.server.master.utils.JDOSupport;
-
-/**
- * A simple state-aware writer of usage records. It just appends them, one by
- * one, to the file whose name is stored in the state.
- * 
- * @author Donal Fellows
- */
-public class UsageRecordRecorder extends JDOSupport<UsageRecord> {
-	private Log log = getLog("Taverna.Server.Webapp");
-	public UsageRecordRecorder() {
-		super(UsageRecord.class);
-	}
-
-	private String logFile = null;
-	private boolean disableDB = false;
-	private ManagementModel state;
-	private Contextualizer contextualizer;
-	private String logDestination;
-	private PrintWriter writer;
-	private Object lock = new Object();
-	private UsageRecordRecorder self;
-
-	/**
-	 * @param state
-	 *            the state to set
-	 */
-	@Required
-	public void setState(ManagementModel state) {
-		this.state = state;
-	}
-
-	@Required
-	public void setSelf(UsageRecordRecorder self) {
-		this.self = self;
-	}
-
-	public void setLogFile(String logFile) {
-		this.logFile = (logFile == null || logFile.equals("none")) ? null : logFile;
-	}
-
-	public void setDisableDB(String disable) {
-		disableDB = "yes".equalsIgnoreCase(disable);
-	}
-
-	/**
-	 * @param contextualizer
-	 *            the system's contextualizer, used to allow making the UR dump
-	 *            file be placed relative to the webapp.
-	 */
-	@Required
-	public void setContextualizer(Contextualizer contextualizer) {
-		this.contextualizer = contextualizer;
-	}
-
-	/**
-	 * Accept a usage record for recording.
-	 * 
-	 * @param usageRecord
-	 *            The serialized usage record to record.
-	 */
-	public void storeUsageRecord(String usageRecord) {
-		String logfile = state.getUsageRecordLogFile();
-		if (logfile == null)
-			logfile = this.logFile;
-		if (logfile != null) {
-			logfile = contextualizer.contextualize(logfile);
-			synchronized (lock) {
-				if (!logfile.equals(logDestination)) {
-					if (writer != null) {
-						writer.close();
-						writer = null;
-					}
-					try {
-						writer = new PrintWriter(new FileWriter(logfile));
-						logDestination = logfile;
-					} catch (IOException e) {
-						log.warn("failed to open usage record log file", e);
-					}
-				}
-				if (writer != null) {
-					writer.println(usageRecord);
-					writer.flush();
-				}
-			}
-		}
-
-		if (!disableDB)
-			saveURtoDB(usageRecord);
-	}
-
-	/**
-	 * How to save a usage record to the database.
-	 * 
-	 * @param usageRecord
-	 *            The serialized usage record to save.
-	 */
-	protected void saveURtoDB(String usageRecord) {
-		UsageRecord ur;
-		try {
-			ur = new UsageRecord(usageRecord);
-		} catch (JAXBException e) {
-			log.warn("failed to deserialize usage record", e);
-			return;
-		}
-
-		try {
-			self.saveURtoDB(ur);
-		} catch (RuntimeException e) {
-			log.warn("failed to save UR to database", e);
-		}
-	}
-
-	@WithinSingleTransaction
-	public void saveURtoDB(UsageRecord ur) {
-		persist(ur);
-	}
-
-	@WithinSingleTransaction
-	public List<JobUsageRecord> getUsageRecords() {
-		@SuppressWarnings("unchecked")
-		Collection<String> urs = (Collection<String>) namedQuery("allByDate")
-				.execute();
-		List<JobUsageRecord> result = new ArrayList<>();
-		for (String ur : urs)
-			try {
-				result.add(JobUsageRecord.unmarshal(ur));
-			} catch (JAXBException e) {
-				log.warn("failed to unmarshal UR", e);
-			}
-		return result;
-	}
-
-	@PreDestroy
-	public void close() {
-		if (writer != null)
-			writer.close();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
deleted file mode 100644
index 13e14cd..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * Resource usage recording mechanism.
- */
-package org.taverna.server.master.usage;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java b/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
deleted file mode 100644
index a1ac04a..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.utils;
-
-import static java.lang.String.format;
-import static java.lang.System.nanoTime;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.TavernaServer.JMX_ROOT;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import org.apache.commons.logging.Log;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.common.version.Version;
-
-/**
- * This class is responsible for timing all invocations of publicly-exposed
- * methods of the webapp. It's connected to the webapp through an AspectJ-style
- * pointcut that targets a custom annotation.
- * 
- * @author Donal Fellows
- */
-@Aspect
-@ManagedResource(objectName = JMX_ROOT + "PerformanceMonitor", description = "The performance monitor for Taverna Server "
-		+ Version.JAVA
-		+ ". Writes to application log using the category 'Taverna.Server.Performance'.")
-public class CallTimeLogger {
-	private long threshold = 4000000;
-	private Log log = getLog("Taverna.Server.Performance");
-
-	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
-	public long getThreshold() {
-		return threshold;
-	}
-
-	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
-	public void setThreshold(long threshold) {
-		this.threshold = threshold;
-	}
-
-	/**
-	 * The timer for this aspect. The wrapped invocation will be timed, and a
-	 * log message written if the configured threshold is exceeded.
-	 * 
-	 * @param call
-	 *            The call being wrapped.
-	 * @return The result of the call.
-	 * @throws Throwable
-	 *             If anything goes wrong with the wrapped call.
-	 * @see System#nanoTime()
-	 */
-	@Around("@annotation(org.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
-	public Object time(ProceedingJoinPoint call) throws Throwable {
-		long fore = nanoTime();
-		try {
-			return call.proceed();
-		} finally {
-			long aft = nanoTime();
-			long elapsed = aft - fore;
-			if (elapsed > threshold)
-				log.info(format("call to %s took %.3fms", call.toShortString(),
-						elapsed / 1000000.0));
-		}
-	}
-
-	/**
-	 * Mark methods that should be counted by the invocation counter.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@Retention(RUNTIME)
-	@Documented
-	@Target(METHOD)
-	public static @interface PerfLogged {
-	}
-}


[08/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
new file mode 100644
index 0000000..ff14986
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.lang.String.format;
+import static java.util.Arrays.fill;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
+import static org.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
+import static org.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
+import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+import javax.security.auth.x500.X500Principal;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriBuilder;
+import javax.xml.ws.handler.MessageContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+import org.taverna.server.master.interfaces.File;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Implementation of a security context.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class SecurityContextDelegate implements TavernaSecurityContext {
+	Log log = LogFactory.getLog("Taverna.Server.Worker");
+	private final UsernamePrincipal owner;
+	private final List<Credential> credentials = new ArrayList<>();
+	private final List<Trust> trusted = new ArrayList<>();
+	private final RemoteRunDelegate run;
+	private final Object lock = new Object();
+	final SecurityContextFactory factory;
+
+	private transient Keystore keystore;
+	private transient Map<URI, String> uriToAliasMap;
+
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected SecurityContextDelegate(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		this.run = run;
+		this.owner = owner;
+		this.factory = factory;
+	}
+
+	@Override
+	public SecurityContextFactory getFactory() {
+		return factory;
+	}
+
+	@Override
+	public UsernamePrincipal getOwner() {
+		return owner;
+	}
+
+	@Override
+	public Credential[] getCredentials() {
+		synchronized (lock) {
+			return credentials.toArray(new Credential[credentials.size()]);
+		}
+	}
+
+	/**
+	 * Get the human-readable name of a principal.
+	 * 
+	 * @param principal
+	 *            The principal being decoded.
+	 * @return A name.
+	 */
+	protected final String getPrincipalName(X500Principal principal) {
+		return factory.x500Utils.getName(principal, CERTIFICATE_FIELD_NAMES);
+	}
+
+	/**
+	 * Cause the current state to be flushed to the database.
+	 */
+	protected final void flushToDB() {
+		factory.db.flushToDisk(run);
+	}
+
+	@Override
+	public void addCredential(Credential toAdd) {
+		synchronized (lock) {
+			int idx = credentials.indexOf(toAdd);
+			if (idx != -1)
+				credentials.set(idx, toAdd);
+			else
+				credentials.add(toAdd);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public void deleteCredential(Credential toDelete) {
+		synchronized (lock) {
+			credentials.remove(toDelete);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public Trust[] getTrusted() {
+		synchronized (lock) {
+			return trusted.toArray(new Trust[trusted.size()]);
+		}
+	}
+
+	@Override
+	public void addTrusted(Trust toAdd) {
+		synchronized (lock) {
+			int idx = trusted.indexOf(toAdd);
+			if (idx != -1)
+				trusted.set(idx, toAdd);
+			else
+				trusted.add(toAdd);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public void deleteTrusted(Trust toDelete) {
+		synchronized (lock) {
+			trusted.remove(toDelete);
+			flushToDB();
+		}
+	}
+
+	@Override
+	public abstract void validateCredential(Credential c)
+			throws InvalidCredentialException;
+
+	@Override
+	public void validateTrusted(Trust t) throws InvalidCredentialException {
+		InputStream contentsAsStream;
+		if (t.certificateBytes != null && t.certificateBytes.length > 0) {
+			contentsAsStream = new ByteArrayInputStream(t.certificateBytes);
+			t.certificateFile = null;
+		} else if (t.certificateFile == null
+				|| t.certificateFile.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty certificateFile");
+		else {
+			contentsAsStream = contents(t.certificateFile);
+			t.certificateBytes = null;
+		}
+		t.serverName = null;
+		if (t.fileType == null || t.fileType.trim().isEmpty())
+			t.fileType = CERTIFICATE_TYPE;
+		t.fileType = t.fileType.trim();
+		try {
+			t.loadedCertificates = CertificateFactory.getInstance(t.fileType)
+					.generateCertificates(contentsAsStream);
+			t.serverName = new ArrayList<>(t.loadedCertificates.size());
+			for (Certificate c : t.loadedCertificates)
+				t.serverName.add(getPrincipalName(((X509Certificate) c)
+						.getSubjectX500Principal()));
+		} catch (CertificateException e) {
+			throw new InvalidCredentialException(e);
+		} catch (ClassCastException e) {
+			// Do nothing; truncates the list of server names
+		}
+	}
+
+	@Override
+	public void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception {
+		// This is how to get the info from Spring Security
+		Authentication auth = securityContext.getAuthentication();
+		if (auth == null)
+			return;
+		auth.getPrincipal();
+		// do nothing else in this implementation
+	}
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// do nothing in this implementation
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders context) {
+		// do nothing in this implementation
+	}
+
+	private UriBuilder getUB() {
+		return factory.uriSource.getRunUriBuilder(run);
+	}
+
+	private RunDatabaseDAO getDAO() {
+		return ((RunDatabase) factory.db).dao;
+	}
+
+	@Nullable
+	private List<X509Certificate> getCerts(URI uri) throws IOException,
+			GeneralSecurityException {
+		return factory.certFetcher.getTrustsForURI(uri);
+	}
+
+	private void installLocalPasswordCredential(List<Credential> credentials,
+			List<Trust> trusts) throws InvalidCredentialException, IOException,
+			GeneralSecurityException {
+		Credential.Password pw = new Credential.Password();
+		pw.id = "run:self";
+		pw.username = PREFIX + run.id;
+		pw.password = getDAO().getSecurityToken(run.id);
+		UriBuilder ub = getUB().segment("").fragment(factory.httpRealm);
+		pw.serviceURI = ub.build();
+		validateCredential(pw);
+		log.info("issuing self-referential credential for " + pw.serviceURI);
+		credentials.add(pw);
+		List<X509Certificate> myCerts = getCerts(pw.serviceURI);
+		if (myCerts != null && myCerts.size() > 0) {
+			Trust t = new Trust();
+			t.loadedCertificates = getCerts(pw.serviceURI);
+			trusts.add(t);
+		}
+	}
+
+	/**
+	 * Builds and transfers a keystore with suitable credentials to the back-end
+	 * workflow execution engine.
+	 * 
+	 * @throws GeneralSecurityException
+	 *             If the manipulation of the keystore, keys or certificates
+	 *             fails.
+	 * @throws IOException
+	 *             If there are problems building the data (should not happen).
+	 * @throws RemoteException
+	 *             If the conveyancing fails.
+	 */
+	@Override
+	public final void conveySecurity() throws GeneralSecurityException,
+			IOException, ImplementationException {
+		RemoteSecurityContext rc = run.run.getSecurityContext();
+
+		List<Trust> trusted = new ArrayList<>(this.trusted);
+		this.trusted.clear();
+		List<Credential> credentials = new ArrayList<>(this.credentials);
+		this.credentials.clear();
+
+		try {
+			installLocalPasswordCredential(credentials, trusted);
+		} catch (Exception e) {
+			log.warn("failed to construct local credential: "
+					+ "interaction service will fail", e);
+		}
+
+		char[] password = null;
+		try {
+			password = generateNewPassword();
+
+			log.info("constructing merged keystore");
+			Truststore truststore = new Truststore(password);
+			Keystore keystore = new Keystore(password);
+			Map<URI, String> uriToAliasMap = new HashMap<>();
+			int trustedCount = 0, keyCount = 0;
+
+			synchronized (lock) {
+				try {
+					for (Trust t : trusted) {
+						if (t == null || t.loadedCertificates == null)
+							continue;
+						for (Certificate cert : t.loadedCertificates)
+							if (cert != null) {
+								truststore.addCertificate(cert);
+								trustedCount++;
+							}
+					}
+
+					this.uriToAliasMap = uriToAliasMap;
+					this.keystore = keystore;
+					for (Credential c : credentials) {
+						addCredentialToKeystore(c);
+						keyCount++;
+					}
+				} finally {
+					this.uriToAliasMap = null;
+					this.keystore = null;
+					credentials.clear();
+					trusted.clear();
+					flushToDB();
+				}
+			}
+
+			byte[] trustbytes = null, keybytes = null;
+			try {
+				trustbytes = truststore.serialize();
+				keybytes = keystore.serialize();
+
+				// Now we've built the security information, ship it off...
+
+				log.info("transfering merged truststore with " + trustedCount
+						+ " entries");
+				rc.setTruststore(trustbytes);
+
+				log.info("transfering merged keystore with " + keyCount
+						+ " entries");
+				rc.setKeystore(keybytes);
+			} finally {
+				if (trustbytes != null)
+					fill(trustbytes, (byte) 0);
+				if (keybytes != null)
+					fill(keybytes, (byte) 0);
+			}
+			rc.setPassword(password);
+
+			log.info("transferring serviceURL->alias map with "
+					+ uriToAliasMap.size() + " entries");
+			rc.setUriToAliasMap(uriToAliasMap);
+		} finally {
+			if (password != null)
+				fill(password, ' ');
+		}
+
+		synchronized (lock) {
+			conveyExtraSecuritySettings(rc);
+		}
+	}
+
+	/**
+	 * Hook that allows additional information to be conveyed to the remote run.
+	 * 
+	 * @param remoteSecurityContext
+	 *            The remote resource that information would be passed to.
+	 * @throws IOException
+	 *             If anything goes wrong with the communication.
+	 */
+	protected void conveyExtraSecuritySettings(
+			RemoteSecurityContext remoteSecurityContext) throws IOException {
+		// Does nothing by default; overrideable
+	}
+
+	/**
+	 * @return A new password with a reasonable level of randomness.
+	 */
+	protected final char[] generateNewPassword() {
+		return randomUUID().toString().toCharArray();
+	}
+
+	/**
+	 * Adds a credential to the current keystore.
+	 * 
+	 * @param alias
+	 *            The alias to create within the keystore.
+	 * @param c
+	 *            The key-pair.
+	 * @throws KeyStoreException
+	 */
+	protected final void addKeypairToKeystore(String alias, Credential c)
+			throws KeyStoreException {
+		if (c.loadedKey == null)
+			throw new KeyStoreException("critical: credential was not verified");
+		if (uriToAliasMap.containsKey(c.serviceURI))
+			log.warn("duplicate URI in alias mapping: " + c.serviceURI);
+		keystore.addKey(alias, c.loadedKey, c.loadedTrustChain);
+		uriToAliasMap.put(c.serviceURI, alias);
+	}
+
+	/**
+	 * Adds a credential to the current keystore.
+	 * 
+	 * @param c
+	 *            The credential to add.
+	 * @throws KeyStoreException
+	 */
+	public abstract void addCredentialToKeystore(Credential c)
+			throws KeyStoreException;
+
+	/**
+	 * Read a file up to {@value #FILE_SIZE_LIMIT}kB in size.
+	 * 
+	 * @param name
+	 *            The path name of the file, relative to the context run's
+	 *            working directory.
+	 * @return A stream of the file's contents.
+	 * @throws InvalidCredentialException
+	 *             If anything goes wrong.
+	 */
+	final InputStream contents(String name) throws InvalidCredentialException {
+		try {
+			File f = (File) factory.fileUtils.getDirEntry(run, name);
+			long size = f.getSize();
+			if (size > CREDENTIAL_FILE_SIZE_LIMIT * 1024)
+				throw new InvalidCredentialException(CREDENTIAL_FILE_SIZE_LIMIT
+						+ "kB limit hit");
+			return new ByteArrayInputStream(f.getContents(0, (int) size));
+		} catch (NoDirectoryEntryException | FilesystemAccessException e) {
+			throw new InvalidCredentialException(e);
+		} catch (ClassCastException e) {
+			throw new InvalidCredentialException("not a file", e);
+		}
+	}
+
+	@Override
+	public Set<String> getPermittedDestroyers() {
+		return run.getDestroyers();
+	}
+
+	@Override
+	public void setPermittedDestroyers(Set<String> destroyers) {
+		run.setDestroyers(destroyers);
+	}
+
+	@Override
+	public Set<String> getPermittedUpdaters() {
+		return run.getWriters();
+	}
+
+	@Override
+	public void setPermittedUpdaters(Set<String> updaters) {
+		run.setWriters(updaters);
+	}
+
+	@Override
+	public Set<String> getPermittedReaders() {
+		return run.getReaders();
+	}
+
+	@Override
+	public void setPermittedReaders(Set<String> readers) {
+		run.setReaders(readers);
+	}
+
+	/**
+	 * Reinstall the credentials and the trust extracted from serialization to
+	 * the database.
+	 * 
+	 * @param credentials
+	 *            The credentials to reinstall.
+	 * @param trust
+	 *            The trusted certificates to reinstall.
+	 */
+	void setCredentialsAndTrust(Credential[] credentials, Trust[] trust) {
+		synchronized (lock) {
+			this.credentials.clear();
+			if (credentials != null)
+				for (Credential c : credentials)
+					try {
+						validateCredential(c);
+						this.credentials.add(c);
+					} catch (InvalidCredentialException e) {
+						log.warn("failed to revalidate credential: " + c, e);
+					}
+			this.trusted.clear();
+			if (trust != null)
+				for (Trust t : trust)
+					try {
+						validateTrusted(t);
+						this.trusted.add(t);
+					} catch (InvalidCredentialException e) {
+						log.warn("failed to revalidate trust assertion: " + t,
+								e);
+					}
+		}
+	}
+
+	static class SecurityStore {
+		private KeyStore ks;
+		private char[] password;
+
+		SecurityStore(char[] password) throws GeneralSecurityException {
+			this.password = password.clone();
+			ks = KeyStore.getInstance("UBER", "BC");
+			try {
+				ks.load(null, this.password);
+			} catch (IOException e) {
+				throw new GeneralSecurityException(
+						"problem initializing blank truststore", e);
+			}
+		}
+
+		final synchronized void setCertificate(String alias, Certificate c)
+				throws KeyStoreException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			ks.setCertificateEntry(alias, c);
+		}
+
+		final synchronized void setKey(String alias, Key key, Certificate[] trustChain)
+				throws KeyStoreException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			ks.setKeyEntry(alias, key, password, trustChain);
+		}
+
+		final synchronized byte[] serialize(boolean logIt)
+				throws GeneralSecurityException {
+			if (ks == null)
+				throw new IllegalStateException("store already written");
+			try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
+				ks.store(stream, password);
+				if (logIt)
+					LogFactory.getLog("Taverna.Server.Worker").debug(
+							"serialized UBER/BC truststore (size: " + ks.size()
+									+ ") with password \""
+									+ new String(password) + "\"");
+				return stream.toByteArray();
+			} catch (IOException e) {
+				throw new GeneralSecurityException(
+						"problem serializing keystore", e);
+			} finally {
+				ks = null;
+				fill(password, ' ');
+			}
+		}
+
+		@Override
+		protected final void finalize() {
+			fill(password, ' ');
+			ks = null;
+		}
+	}
+
+	/**
+	 * A trust store that can only be added to or serialized. Only trusted
+	 * certificates can be placed in it.
+	 * 
+	 * @author Donal Fellows
+	 */
+	class Truststore extends SecurityStore {
+		Truststore(char[] password) throws GeneralSecurityException {
+			super(password);
+		}
+
+		/**
+		 * Add a trusted certificate to the truststore. No certificates can be
+		 * added after the truststore is serialized.
+		 * 
+		 * @param cert
+		 *            The certificate (typically belonging to a root CA) to add.
+		 * @throws KeyStoreException
+		 *             If anything goes wrong.
+		 */
+		public void addCertificate(Certificate cert) throws KeyStoreException {
+			X509Certificate c = (X509Certificate) cert;
+			String alias = format("trustedcert#%s#%s#%s",
+					getPrincipalName(c.getSubjectX500Principal()),
+					getPrincipalName(c.getIssuerX500Principal()),
+					factory.x500Utils.getSerial(c));
+			setCertificate(alias, c);
+			if (log.isDebugEnabled() && factory.logSecurityDetails)
+				log.debug("added cert with alias \"" + alias + "\" of type "
+						+ c.getClass().getCanonicalName());
+		}
+
+		/**
+		 * Get the byte serialization of this truststore. This can only be
+		 * fetched exactly once.
+		 * 
+		 * @return The serialization.
+		 * @throws GeneralSecurityException
+		 *             If anything goes wrong.
+		 */
+		public byte[] serialize() throws GeneralSecurityException {
+			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
+		}
+	}
+
+	/**
+	 * A key store that can only be added to or serialized. Only keys can be
+	 * placed in it.
+	 * 
+	 * @author Donal Fellows
+	 */
+	class Keystore extends SecurityStore {
+		Keystore(char[] password) throws GeneralSecurityException {
+			super(password);
+		}
+
+		/**
+		 * Add a key to the keystore. No keys can be added after the keystore is
+		 * serialized.
+		 * 
+		 * @param alias
+		 *            The alias of the key.
+		 * @param key
+		 *            The secret/private key to add.
+		 * @param trustChain
+		 *            The trusted certificate chain of the key. Should be
+		 *            <tt>null</tt> for secret keys.
+		 * @throws KeyStoreException
+		 *             If anything goes wrong.
+		 */
+		public void addKey(String alias, Key key, Certificate[] trustChain)
+				throws KeyStoreException {
+			setKey(alias, key, trustChain);
+			if (log.isDebugEnabled() && factory.logSecurityDetails)
+				log.debug("added key with alias \"" + alias + "\" of type "
+						+ key.getClass().getCanonicalName());
+		}
+
+		/**
+		 * Get the byte serialization of this keystore. This can only be fetched
+		 * exactly once.
+		 * 
+		 * @return The serialization.
+		 * @throws GeneralSecurityException
+		 *             If anything goes wrong.
+		 */
+		public byte[] serialize() throws GeneralSecurityException {
+			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
new file mode 100644
index 0000000..d36d2da
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.lang.String.format;
+import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.rmi.RemoteException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.ws.handler.MessageContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.taverna.server.localworker.remote.RemoteSecurityContext;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.utils.X500Utils;
+
+/**
+ * Factoring out of the part of the security context handling that actually
+ * deals with the different types of credentials.
+ * 
+ * @author Donal Fellows
+ */
+class SecurityContextDelegateImpl extends SecurityContextDelegate {
+	private static final char USERNAME_PASSWORD_SEPARATOR = '\u0000';
+	private static final String USERNAME_PASSWORD_KEY_ALGORITHM = "DUMMY";
+	/** What passwords are encoded as. */
+	private static final Charset UTF8 = Charset.forName("UTF-8");
+
+	private X500Utils x500Utils;
+
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected SecurityContextDelegateImpl(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		super(run, owner, factory);
+		this.x500Utils = factory.x500Utils;
+	}
+
+	@Override
+	public void validateCredential(Credential c)
+			throws InvalidCredentialException {
+		try {
+			if (c instanceof Credential.Password)
+				validatePasswordCredential((Credential.Password) c);
+			else if (c instanceof Credential.KeyPair)
+				validateKeyCredential((Credential.KeyPair) c);
+			else
+				throw new InvalidCredentialException("unknown credential type");
+		} catch (InvalidCredentialException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new InvalidCredentialException(e);
+		}
+	}
+
+	@Override
+	public void addCredentialToKeystore(Credential c) throws KeyStoreException {
+		try {
+			if (c instanceof Credential.Password)
+				addUserPassToKeystore((Credential.Password) c);
+			else if (c instanceof Credential.KeyPair)
+				addKeypairToKeystore((Credential.KeyPair) c);
+			else
+				throw new KeyStoreException("unknown credential type");
+		} catch (KeyStoreException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new KeyStoreException(e);
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * Tests whether the given username+password credential descriptor is valid.
+	 * If it is invalid, an exception will be thrown describing what the problem
+	 * is. Validation mainly consists of listing what the username is.
+	 * 
+	 * @param passwordDescriptor
+	 *            The credential descriptor to validate.
+	 * @throws InvalidCredentialException
+	 *             If the username is empty. NB: the password may be empty!
+	 *             That's legal (if unwise).
+	 */
+	protected void validatePasswordCredential(
+			Credential.Password passwordDescriptor)
+			throws InvalidCredentialException {
+		if (passwordDescriptor.username == null
+				|| passwordDescriptor.username.trim().isEmpty())
+			throw new InvalidCredentialException("absent or empty username");
+		if (passwordDescriptor.serviceURI == null)
+			throw new InvalidCredentialException("absent service URI");
+		String keyToSave = passwordDescriptor.username
+				+ USERNAME_PASSWORD_SEPARATOR + passwordDescriptor.password;
+		passwordDescriptor.loadedKey = encodeKey(keyToSave);
+		passwordDescriptor.loadedTrustChain = null;
+	}
+
+	private static Key encodeKey(String key) {
+		return new SecretKeySpec(key.getBytes(UTF8),
+				USERNAME_PASSWORD_KEY_ALGORITHM);
+	}
+
+	/**
+	 * Adds a username/password credential pair to the current keystore.
+	 * 
+	 * @param userpassCredential
+	 *            The username and password.
+	 * @throws KeyStoreException
+	 */
+	protected void addUserPassToKeystore(Credential.Password userpassCredential)
+			throws KeyStoreException {
+		String alias = format("password#%s",
+				userpassCredential.serviceURI.toASCIIString());
+		addKeypairToKeystore(alias, userpassCredential);
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+	/**
+	 * Tests whether the given key-pair credential descriptor is valid. If it is
+	 * invalid, an exception will be thrown describing what the problem is.
+	 * 
+	 * @param keypairDescriptor
+	 *            The descriptor to validate.
+	 * @throws InvalidCredentialException
+	 *             If the descriptor is invalid
+	 * @throws KeyStoreException
+	 *             If we don't understand the keystore type or the contents of
+	 *             the keystore
+	 * @throws NoSuchAlgorithmException
+	 *             If the keystore is of a known type but we can't comprehend
+	 *             its security
+	 * @throws CertificateException
+	 *             If the keystore does not include enough information about the
+	 *             trust chain of the keypair
+	 * @throws UnrecoverableKeyException
+	 *             If we can't get the key out of the keystore
+	 * @throws IOException
+	 *             If we can't read the keystore for prosaic reasons (e.g., file
+	 *             absent)
+	 */
+	protected void validateKeyCredential(Credential.KeyPair keypairDescriptor)
+			throws InvalidCredentialException, KeyStoreException,
+			NoSuchAlgorithmException, CertificateException, IOException,
+			UnrecoverableKeyException {
+		if (keypairDescriptor.credentialName == null
+				|| keypairDescriptor.credentialName.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty credentialName");
+
+		InputStream contentsAsStream;
+		if (keypairDescriptor.credentialBytes != null
+				&& keypairDescriptor.credentialBytes.length > 0) {
+			contentsAsStream = new ByteArrayInputStream(
+					keypairDescriptor.credentialBytes);
+			keypairDescriptor.credentialFile = null;
+		} else if (keypairDescriptor.credentialFile == null
+				|| keypairDescriptor.credentialFile.trim().isEmpty())
+			throw new InvalidCredentialException(
+					"absent or empty credentialFile");
+		else {
+			contentsAsStream = contents(keypairDescriptor.credentialFile);
+			keypairDescriptor.credentialBytes = new byte[0];
+		}
+		if (keypairDescriptor.fileType == null
+				|| keypairDescriptor.fileType.trim().isEmpty())
+			keypairDescriptor.fileType = KeyStore.getDefaultType();
+		keypairDescriptor.fileType = keypairDescriptor.fileType.trim();
+
+		KeyStore ks = KeyStore.getInstance(keypairDescriptor.fileType);
+		char[] password = keypairDescriptor.unlockPassword.toCharArray();
+		ks.load(contentsAsStream, password);
+
+		try {
+			keypairDescriptor.loadedKey = ks.getKey(
+					keypairDescriptor.credentialName, password);
+		} catch (UnrecoverableKeyException ignored) {
+			keypairDescriptor.loadedKey = ks.getKey(
+					keypairDescriptor.credentialName, new char[0]);
+		}
+		if (keypairDescriptor.loadedKey == null)
+			throw new InvalidCredentialException(
+					"no such credential in key store");
+		keypairDescriptor.loadedTrustChain = ks
+				.getCertificateChain(keypairDescriptor.credentialName);
+		if (keypairDescriptor.loadedTrustChain == null
+				|| keypairDescriptor.loadedTrustChain.length == 0)
+			throw new InvalidCredentialException(
+					"could not establish trust chain for credential");
+	}
+
+	/**
+	 * Adds a key-pair to the current keystore.
+	 * 
+	 * @param c
+	 *            The key-pair.
+	 * @throws KeyStoreException
+	 */
+	protected void addKeypairToKeystore(Credential.KeyPair c)
+			throws KeyStoreException {
+		X509Certificate subjectCert = (X509Certificate) c.loadedTrustChain[0];
+		String alias = format("keypair#%s#%s#%s",
+				getPrincipalName(subjectCert.getSubjectX500Principal()),
+				getPrincipalName(subjectCert.getIssuerX500Principal()),
+				x500Utils.getSerial(subjectCert));
+		addKeypairToKeystore(alias, c);
+	}
+}
+
+/**
+ * Special subclass that adds support for HELIO project security tokens.
+ * 
+ * @author Donal Fellows
+ */
+class HelioSecurityContextDelegateImpl extends SecurityContextDelegateImpl {
+	/**
+	 * Initialise the context delegate.
+	 * 
+	 * @param run
+	 *            What workflow run is this for?
+	 * @param owner
+	 *            Who owns the workflow run?
+	 * @param factory
+	 *            What class built this object?
+	 */
+	protected HelioSecurityContextDelegateImpl(RemoteRunDelegate run,
+			UsernamePrincipal owner, SecurityContextFactory factory) {
+		super(run, owner, factory);
+	}
+
+	private Log log = LogFactory.getLog("Taverna.Server.Worker");
+	/** The name of the HTTP header holding the CIS token. */
+	private static final String HELIO_CIS_TOKEN = "X-Helio-CIS";
+	private transient String helioToken;
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// does nothing
+		@SuppressWarnings("unchecked")
+		Map<String, List<String>> headers = (Map<String, List<String>>) context
+				.get(HTTP_REQUEST_HEADERS);
+		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
+			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders context) {
+		// does nothing
+		MultivaluedMap<String, String> headers = context.getRequestHeaders();
+		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
+			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
+	}
+
+	@Override
+	protected void conveyExtraSecuritySettings(RemoteSecurityContext rc)
+			throws RemoteException {
+		try {
+			if (factory.supportHelioToken && helioToken != null) {
+				if (factory.logSecurityDetails)
+					log.info("transfering HELIO CIS token: " + helioToken);
+				rc.setHelioToken(helioToken);
+			}
+		} finally {
+			helioToken = null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
new file mode 100644
index 0000000..cbccf34
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2011-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static java.security.Security.addProvider;
+import static java.security.Security.getProvider;
+import static java.security.Security.removeProvider;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
+
+import java.io.Serializable;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.beans.factory.annotation.Value;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+import org.taverna.server.master.utils.CertificateChainFetcher;
+import org.taverna.server.master.utils.FilenameUtils;
+import org.taverna.server.master.utils.UsernamePrincipal;
+import org.taverna.server.master.utils.X500Utils;
+
+/**
+ * Singleton factory. Really is a singleton (and is also very trivial); the
+ * singleton-ness is just about limiting the number of instances of this around
+ * even when lots of serialization is going on.
+ * 
+ * @see Serializable
+ * @author Donal Fellows
+ */
+public class SecurityContextFactory implements
+		org.taverna.server.master.interfaces.SecurityContextFactory {
+	private static final long serialVersionUID = 12345678987654321L;
+	private static SecurityContextFactory instance;
+	transient RunDBSupport db;
+	transient FilenameUtils fileUtils;
+	transient X500Utils x500Utils;
+	transient UriBuilderFactory uriSource;
+	transient CertificateChainFetcher certFetcher;
+	transient String httpRealm;
+	private transient PasswordIssuer passwordIssuer;
+	private transient BouncyCastleProvider provider;
+
+	/**
+	 * Whether to support HELIO CIS tokens.
+	 */
+	@Value("${helio.cis.enableTokenPassing}")
+	boolean supportHelioToken;
+
+	/**
+	 * Whether to log the details of security (passwords, etc).
+	 */
+	@Value("${log.security.details}")
+	boolean logSecurityDetails;
+
+	private Log log() {
+		return getLog("Taverna.Server.Worker.Security");
+	}
+
+	private void installAsInstance(SecurityContextFactory handle) {
+		instance = handle;
+	}
+
+	@PreDestroy
+	void removeAsSingleton() {
+		installAsInstance(null);
+		try {
+			if (provider != null)
+				removeProvider(provider.getName());
+		} catch (SecurityException e) {
+			log().warn(
+					"failed to remove BouncyCastle security provider; "
+							+ "might be OK if configured in environment", e);
+		}
+	}
+
+	@PostConstruct
+	void setAsSingleton() {
+		installAsInstance(this);
+		if (getProvider(PROVIDER_NAME) == null)
+			try {
+				provider = new BouncyCastleProvider();
+				if (addProvider(provider) == -1)
+					provider = null;
+			} catch (SecurityException e) {
+				log().warn(
+						"failed to install BouncyCastle security provider; "
+								+ "might be OK if already configured", e);
+				provider = null;
+			}
+	}
+
+	@Required
+	public void setRunDatabase(RunDBSupport db) {
+		this.db = db;
+	}
+
+	@Required
+	public void setCertificateFetcher(CertificateChainFetcher fetcher) {
+		this.certFetcher = fetcher;
+	}
+
+	@Required
+	public void setFilenameConverter(FilenameUtils fileUtils) {
+		this.fileUtils = fileUtils;
+	}
+
+	@Required
+	public void setX500Utils(X500Utils x500Utils) {
+		this.x500Utils = x500Utils;
+	}
+
+	@Required
+	public void setUriSource(UriBuilderFactory uriSource) {
+		this.uriSource = uriSource;
+	}
+
+	@Required
+	public void setHttpRealm(String realm) {
+		this.httpRealm = realm; //${http.realmName}
+	}
+
+	@Required
+	public void setPasswordIssuer(PasswordIssuer issuer) {
+		this.passwordIssuer = issuer;
+	}
+
+	@Override
+	public SecurityContextDelegate create(TavernaRun run,
+			UsernamePrincipal owner) throws Exception {
+		Log log = log();
+		if (log.isDebugEnabled())
+			log.debug("constructing security context delegate for " + owner);
+		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
+		return new HelioSecurityContextDelegateImpl(rrd, owner, this);
+	}
+
+	private Object readResolve() {
+		if (instance == null)
+			installAsInstance(this);
+		return instance;
+	}
+
+	public String issueNewPassword() {
+		return passwordIssuer.issue();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
new file mode 100644
index 0000000..793d291
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static org.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
+
+import java.text.MessageFormat;
+
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Completion notifier that sends messages by email.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleFormattedCompletionNotifier implements CompletionNotifier {
+	@Required
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * @param subject
+	 *            The subject of the notification email.
+	 */
+	@Required
+	public void setSubject(String subject) {
+		this.subject = subject;
+	}
+
+	/**
+	 * @param messageFormat
+	 *            The template for the body of the message to send. Parameter #0
+	 *            will be substituted with the ID of the job, and parameter #1
+	 *            will be substituted with the exit code.
+	 */
+	public void setMessageFormat(String messageFormat) {
+		this.format = new MessageFormat(messageFormat);
+	}
+
+	private String name;
+	private String subject;
+	private MessageFormat format = new MessageFormat(NOTIFY_MESSAGE_FORMAT);
+
+	@Override
+	public String makeCompletionMessage(String name, RemoteRunDelegate run,
+			int code) {
+		return format.format(new Object[] { name, code });
+	}
+
+	@Override
+	public String makeMessageSubject(String name, RemoteRunDelegate run,
+			int code) {
+		return subject;
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
new file mode 100644
index 0000000..cf67853
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
@@ -0,0 +1,105 @@
+package org.taverna.server.master.worker;
+
+import java.io.StringWriter;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.common.version.Version;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.UriBuilderFactory;
+
+public class VelocityCompletionNotifier implements CompletionNotifier {
+	private String subject;
+	private VelocityEngine engine;
+	private Template template;
+	private String name;
+	private String templateName;
+	private UriBuilderFactory ubf;
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param subject
+	 *            The subject of the notification email.
+	 */
+	@Required
+	public void setSubject(String subject) {
+		this.subject = subject;
+	}
+
+	/**
+	 * @param engine
+	 *            The configured Apache Velocity engine.
+	 */
+	@Required
+	public void setVelocityEngine(VelocityEngine engine) {
+		this.engine = engine;
+	}
+
+	/**
+	 * @param uriBuilderFactory
+	 *            The configured URI builder factory.
+	 */
+	@Required
+	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
+		this.ubf = uriBuilderFactory;
+	}
+
+	/**
+	 * @param name
+	 *            The name of the template.
+	 */
+	@Required
+	public void setName(String name) {
+		this.name = name;
+		this.templateName = getClass().getName() + "_" + name + ".vtmpl";
+	}
+
+	private Template getTemplate() {
+		if (template == null)
+			synchronized(this) {
+				if (template == null)
+					template = engine.getTemplate(templateName);
+			}
+		return template;
+	}
+
+	@Override
+	public String makeCompletionMessage(String name, RemoteRunDelegate run,
+			int code) {
+		VelocityContext ctxt = new VelocityContext();
+		ctxt.put("id", name);
+		ctxt.put("uriBuilder", ubf.getRunUriBuilder(run));
+		ctxt.put("name", run.getName());
+		ctxt.put("creationTime", run.getCreationTimestamp());
+		ctxt.put("startTime", run.getStartTimestamp());
+		ctxt.put("finishTime", run.getFinishTimestamp());
+		ctxt.put("expiryTime", run.getExpiry());
+		ctxt.put("serverVersion", Version.JAVA);
+		for (Listener l : run.getListeners())
+			if (l.getName().equals("io")) {
+				for (String p : l.listProperties())
+					try {
+						ctxt.put("prop_" + p, l.getProperty(p));
+					} catch (NoListenerException e) {
+						// Ignore...
+					}
+				break;
+			}
+		StringWriter sw = new StringWriter();
+		getTemplate().merge(ctxt, sw);
+		return sw.toString();
+	}
+
+	@Override
+	public String makeMessageSubject(String name, RemoteRunDelegate run,
+			int code) {
+		return subject;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
new file mode 100644
index 0000000..1abe617
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2010-2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+
+/**
+ * Profile of the getters and setters in a worker system. Ensures that the
+ * persisted state matches the public view on the state model at least fairly
+ * closely.
+ * 
+ * @author Donal Fellows
+ */
+public interface WorkerModel extends PolicyLimits {
+
+	/**
+	 * @param defaultLifetime
+	 *            how long a workflow run should live by default, in minutes.
+	 */
+	public abstract void setDefaultLifetime(int defaultLifetime);
+
+	/**
+	 * @return how long a workflow run should live by default, in minutes.
+	 */
+	public abstract int getDefaultLifetime();
+
+	/**
+	 * @param maxRuns
+	 *            the maximum number of extant workflow runs
+	 */
+	public abstract void setMaxRuns(int maxRuns);
+
+	/**
+	 * @param factoryProcessNamePrefix
+	 *            the prefix used for factory processes in RMI
+	 */
+	public abstract void setFactoryProcessNamePrefix(
+			String factoryProcessNamePrefix);
+
+	/**
+	 * @return the prefix used for factory processes in RMI
+	 */
+	public abstract String getFactoryProcessNamePrefix();
+
+	/**
+	 * @param executeWorkflowScript
+	 *            the script to run to actually run a workflow
+	 */
+	public abstract void setExecuteWorkflowScript(String executeWorkflowScript);
+
+	/**
+	 * @return the script to run to actually run a workflow
+	 */
+	public abstract String getExecuteWorkflowScript();
+
+	/**
+	 * @param extraArgs
+	 *            the extra arguments to pass into the workflow runner
+	 */
+	public abstract void setExtraArgs(String[] extraArgs);
+
+	/**
+	 * @return the extra arguments to pass into the workflow runner
+	 */
+	public abstract String[] getExtraArgs();
+
+	/**
+	 * @param waitSeconds
+	 *            the number of seconds to wait for subprocesses to start
+	 */
+	public abstract void setWaitSeconds(int waitSeconds);
+
+	/**
+	 * @return the number of seconds to wait for subprocesses to start
+	 */
+	public abstract int getWaitSeconds();
+
+	/**
+	 * @param sleepMS
+	 *            milliseconds to wait between polling for a started
+	 *            subprocess's status
+	 */
+	public abstract void setSleepMS(int sleepMS);
+
+	/**
+	 * @return milliseconds to wait between polling for a started subprocess's
+	 *         status
+	 */
+	public abstract int getSleepMS();
+
+	/**
+	 * @param serverWorkerJar
+	 *            the full path name of the file system access worker
+	 *            subprocess's implementation JAR
+	 */
+	public abstract void setServerWorkerJar(String serverWorkerJar);
+
+	/**
+	 * @return the full path name of the file system access worker subprocess's
+	 *         implementation JAR
+	 */
+	public abstract String getServerWorkerJar();
+
+	/**
+	 * @param javaBinary
+	 *            the full path name to the Java binary to use
+	 */
+	public abstract void setJavaBinary(String javaBinary);
+
+	/**
+	 * @return the full path name to the Java binary to use
+	 */
+	public abstract String getJavaBinary();
+
+	/**
+	 * @param registryPort
+	 *            what port is the RMI registry on
+	 */
+	public abstract void setRegistryPort(int registryPort);
+
+	/**
+	 * @return what port is the RMI registry on
+	 */
+	public abstract int getRegistryPort();
+
+	/**
+	 * @param registryHost
+	 *            what host (network interface) is the RMI registry on
+	 */
+	public abstract void setRegistryHost(String registryHost);
+
+	/**
+	 * @return what host (network interface) is the RMI registry on
+	 */
+	public abstract String getRegistryHost();
+
+	/**
+	 * @param serverForkerJar
+	 *            the full path name of the impersonation engine's
+	 *            implementation JAR
+	 */
+	public abstract void setServerForkerJar(String serverForkerJar);
+
+	/**
+	 * @return the full path name of the impersonation engine's implementation
+	 *         JAR
+	 */
+	public abstract String getServerForkerJar();
+
+	/**
+	 * @param passwordFile
+	 *            the full path name of a file containing a password to use with
+	 *            sudo (or empty for none)
+	 */
+	public abstract void setPasswordFile(String passwordFile);
+
+	/**
+	 * @return the full path name of a file containing a password to use with
+	 *         sudo (or empty for none)
+	 */
+	public abstract String getPasswordFile();
+
+	/**
+	 * @param operatingLimit
+	 *            the maximum number of runs in the
+	 *            {@linkplain Status#Operating operating} state at once
+	 */
+	public abstract void setOperatingLimit(int operatingLimit);
+
+	@Override
+	void setPermittedWorkflowURIs(List<URI> permittedWorkflows);
+
+	/**
+	 * @return the full path name of the RMI registry subprocess's
+	 *         implementation JAR
+	 */
+	String getRegistryJar();
+
+	/**
+	 * @param rmiRegistryJar
+	 *            the full path name of the RMI registry subprocess's
+	 *            implementation JAR
+	 */
+	void setRegistryJar(String rmiRegistryJar);
+
+	/**
+	 * @return whether a run should generate provenance information by default
+	 */
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param generateProvenance
+	 *            whether a run should generate provenance information by
+	 *            default
+	 */
+	void setGenerateProvenance(boolean generateProvenance);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
new file mode 100644
index 0000000..6007f88
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * A Taverna Server back-end that works by forking off workflow executors.
+ */
+package org.taverna.server.master.worker;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/replacementscripts/executeworkflow.bat
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/replacementscripts/executeworkflow.bat b/taverna-server-webapp/src/main/replacementscripts/executeworkflow.bat
new file mode 100644
index 0000000..c678855
--- /dev/null
+++ b/taverna-server-webapp/src/main/replacementscripts/executeworkflow.bat
@@ -0,0 +1,25 @@
+@ECHO OFF
+
+REM Taverna startup script
+
+REM distribution directory
+set TAVERNA_HOME=%~dp0
+
+REM 300 MB memory, 140 MB for classes
+set ARGS=-Xmx300m -XX:MaxPermSize=140m
+
+REM Taverna system properties
+set ARGS=%ARGS% "-Draven.profile=file:%TAVERNA_HOME%conf/current-profile.xml"
+set ARGS=%ARGS% -Djava.system.class.loader=net.sf.taverna.raven.prelauncher.BootstrapClassLoader 
+set ARGS=%ARGS% -Draven.launcher.app.main=net.sf.taverna.t2.commandline.CommandLineLauncher
+set ARGS=%ARGS% -Draven.launcher.show_splashscreen=false
+set ARGS=%ARGS% -Djava.awt.headless=true
+set ARGS=%ARGS% "-Dtaverna.startup=%TAVERNA_HOME%."
+IF NOT x%RAVEN_APPHOME%==x SET ARGS=%ARGS% "-Draven.launcher.app.home=%RAVEN_APPHOME%"
+IF NOT x%TAVERNA_RUN_ID%==x SET ARGS=%ARGS% "-Dtaverna.runid=%TAVERNA_RUN_ID%"
+IF NOT x%INTERACTION_HOST%==x SET ARGS=%ARGS% "-Dtaverna.interaction.host=%INTERACTION_HOST%"
+IF NOT x%INTERACTION_PORT%==x SET ARGS=%ARGS% "-Dtaverna.interaction.port=%INTERACTION_PORT%"
+IF NOT x%INTERACTION_WEBDAV%==x SET ARGS=%ARGS% "-Dtaverna.interaction.webdav_path=%INTERACTION_WEBDAV%"
+IF NOT x%INTERACTION_FEED%==x SET ARGS=%ARGS% "-Dtaverna.interaction.feed_path=%INTERACTION_FEED%"
+
+java %ARGS% -jar "%TAVERNA_HOME%lib\prelauncher-2.3.jar" %*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/replacementscripts/executeworkflow.sh
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/replacementscripts/executeworkflow.sh b/taverna-server-webapp/src/main/replacementscripts/executeworkflow.sh
new file mode 100644
index 0000000..e9e1d36
--- /dev/null
+++ b/taverna-server-webapp/src/main/replacementscripts/executeworkflow.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+set -e
+
+# 300 MB memory, 140 MB for classes
+memlimit=-Xmx300m
+permsize=-XX:MaxPermSize=140m
+
+## Parse the command line to extract the pieces to move around to before or
+## after the JAR filename...
+pre=-Djava.awt.headless=true 
+post=
+for arg
+do
+    case $arg in
+	-JXmx*) memlimit=`echo $arg | sed 's/-JX/-X/'` ;;
+	-JXX:MaxPermSize=*) permsize=`echo $arg | sed 's/-JXX/-XX/'` ;;
+	-J*) pre="$pre `echo $arg | sed 's/-J/-/'`" ;;
+	-D*) pre="$pre $arg" ;;
+	*) post="$post \"$arg\"" ;;
+    esac
+done
+if test "xx" = "x${post}x"; then
+    echo "Missing arguments! Bug in argument processing?" >&2
+    exit 1
+fi
+eval set x $post
+shift
+
+## resolve links - $0 may be a symlink
+prog="$0"
+
+real_path() {
+    readlink -m "$1" 2>/dev/null || python -c 'import os,sys;print os.path.realpath(sys.argv[1])' "$1"
+}
+
+realprog=`real_path "$prog"`
+taverna_home=`dirname "$realprog"`
+javabin=java
+if test -x "$JAVA_HOME/bin/java"; then
+    javabin="$JAVA_HOME/bin/java"
+fi
+APPHOME_PROP= 
+if test x != "x$TAVERNA_APPHOME"; then
+    APPHOME_PROP="-Dtaverna.app.home=$TAVERNA_APPHOME"
+fi
+RUNID_PROP= 
+if test x != "x$TAVERNA_RUN_ID"; then
+    RUNID_PROP="-Dtaverna.runid=$TAVERNA_RUN_ID"
+fi
+INTERACTION_PROPS=-Dtaverna.interaction.ignore_requests=true
+if test x != "x$INTERACTION_HOST"; then
+    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.host=$INTERACTION_HOST"
+    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.port=$INTERACTION_PORT"
+    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.webdav_path=$INTERACTION_WEBDAV"
+    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.feed_path=$INTERACTION_FEED"
+    if test x != "x$INTERACTION_PUBLISH"; then
+    	INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.publishAddressOverride=$INTERACTION_PUBLISH"
+    fi
+fi
+
+MainClass=net.sf.taverna.t2.commandline.CommandLineLauncher
+
+echo "pid:$$"
+exec "$javabin" $memlimit $permsize \
+  "-Dlog4j.configuration=file://$taverna_home/conf/log4j.properties " \
+  "-Djava.util.logging.config.file=$taverna_home/conf/logging.properties " \
+  "-Dtaverna.app.startup=$taverna_home" -Dtaverna.interaction.ignore_requests=true \
+  $APPHOME_PROP $RUNID_PROP $INTERACTION_PROPS -Djava.awt.headless=true \
+  -Dcom.sun.net.ssl.enableECC=false -Djsse.enableSNIExtension=false $pre \
+  -jar "$taverna_home/lib/taverna-command-line-0.1.1.jar" \
+  ${1+"$@"}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/admin.html
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/admin.html b/taverna-server-webapp/src/main/resources/admin.html
new file mode 100644
index 0000000..a80a783
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/admin.html
@@ -0,0 +1,240 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Taverna Server ${project.version} Administration Interface</title>
+<link id="admin" href="admin" />
+<script type="text/javascript" src="admin/static/jquery-1.8.0.min.js"></script>
+<script type="text/javascript" src="admin/static/jquery-ui-1.8.23.custom.min.js"></script>
+<script type="text/javascript" src="admin/static/admin.js"></script>
+<link href="admin/static/jquery-ui-1.8.23.custom.css" rel="stylesheet" type="text/css" />
+
+</head>
+<body>
+<img height="70" style="float:left" src="admin/static/t2cogs.png">
+<h1>Taverna Server ${project.version} Administration Interface</h1>
+<br clear="left"/>
+<div id="body">
+<ul>
+  <li><a href="#t-global">Global Settings</a></li>
+  <li><a href="#t-users">Users</a></li>
+  <li><a href="#t-workflows">Workflows</a></li>
+  <li><a href="#t-usage">Usage Records</a></li>
+  <li><a href="#t-worker">Local Worker Configuration</a></li>
+</ul>
+  
+<div id="t-global">
+<label title="The number of invocations of the main interface webapp that have been done. Be aware that one service call can result in many invocations due to resource resolution." for="invokationCount">Invocation Count:</label>
+<span title="The number of invocations of the main interface webapp that have been done. Be aware that one service call can result in many invocations due to resource resolution." id="invokationCount">0</span>
+<br>
+<label title="The number of runs that currently exist." for="runCount">Run Count:</label>
+<span title="The number of runs that currently exist." id="runCount">0</span>
+<br>
+<label title="The number of runs that are currently operating." for="operatingCount">Operating Run Count:</label>
+<span title="The number of runs that are currently operating." id="operatingCount">0</span>
+<br>
+<label title="Whether workflow runs should create provenance traces by default. Users can explicitly override this." for="generateProvenance">Generate Provenance by Default</label>
+<input type="checkbox" id="generateProvenance" />
+<br>
+<label title="The time it took for the back-end engine to start up, in seconds. Should usually be short." for="startupTime">Back-End Startup Time (seconds):</label>
+<span title="The time it took for the back-end engine to start up, in seconds. Should usually be short." id="startupTime">0</span>
+<br>
+<label title="The exit code from the last time the back-end was shut down. Blank if the back end has never been shut down while the current webapp instance is running (i.e., since the last boot of the container)." for="lastExitCode">Back-End Last Exit Code:</label>
+<span title="The exit code from the last time the back-end was shut down. Blank if the back end has never been shut down while the current webapp instance is running (i.e., since the last boot of the container)." id="lastExitCode"></span>
+<p>
+<label title="Whether new workflow runs should be created. Disabling this does not prevent existing runs from executing." for="allowNew">Allow New Runs</label>
+<input type="checkbox" id="allowNew" />
+<label title="Whether to record the workflows being run by users. Very noisy due to length of workflow documents, occasionally useful." for="logWorkflows">Log Executed Workflows</label>
+<input type="checkbox" id="logWorkflows" />
+<label title="Whether to record exceptions generated by users in the code (as well as converting them to faults and error responses). Useful for debugging, but noisy." for="logFaults">Log User Exceptions</label>
+<input type="checkbox" id="logFaults" />
+<p>
+<label title="The maximum number of workflow runs that can exist at once, in any state." for="runLimit">Maximum Simultaneous Existing Workflow Runs</label>
+<input title="The maximum number of workflow runs that can exist at once, in any state." id="runLimit" size="3" />
+<br>
+<label title="The maximum number of workflow runs that can be executing at once." for="operatingLimit">Maximum Simultaneous Executing Workflow Runs</label>
+<input title="The maximum number of workflow runs that can be executing at once." id="operatingLimit" size="3" />
+<br>
+<label title="How long to allow a workflow to execute for by default (clients can change this), in minutes." for="defaultLifetime">Default Run Lifetime (minutes)</label>
+<input title="How long to allow a workflow to execute for by default (clients can change this), in minutes." id="defaultLifetime" size="7" />
+</div><!-- t-global -->
+
+<div id="t-users">
+<table id="userList">
+  <tr><th>Username<th>System Username</tr>
+</table>
+<h3>Add a user</h3>
+<table border=1>
+  <tr>
+    <td><label title="The user name to create." for="newUsername">Username</label>
+    <td><input title="The user name to create." size=12 id="newUsername" />
+  </tr>
+  <tr>
+    <td><label title="The password to use for the user." for="newPassword">Password</label>
+    <td><input title="The password to use for the user." size=12 id="newPassword" type="password"/>
+  </tr>
+  <tr>
+    <td><label title="The system account to run the user's workflows in; leave blank for the default." for="newSysID">System ID</label>
+    <td><input title="The system account to run the user's workflows in; leave blank for the default." size=12 id="newSysID" />
+  </tr>
+  <tr><td colspan=2>
+    <label title="Whether to allow this user to log in at all." for="newEnabled">Enabled</label>
+    <input type="checkbox" id="newEnabled" />
+    <label title="Whether the user has administrative privileges (can see all workflow runs, can access the administration page)." for="newAdmin">Admin</label>
+    <input type="checkbox" id="newAdmin" />
+  </td></tr>
+  <tr><td colspan=2>
+    <button id="makeNewUser">Create a new user</button>
+  </td></tr>
+</table>
+</div><!-- t-users -->
+
+<div id="t-workflows">
+<label title="Workflow URIs to limit execution to." for="workflows">Workflow URIs (one per line)</label>
+<br>
+<textarea title="Workflow URIs to limit execution to." rows="5" cols="60" id="workflows"></textarea>
+<p>
+<button id="saveWorkflows">Save</button> <button id="refreshWorkflows">Refresh</button> <button id="emptyWorkflows">Empty URIs list</button>
+</div>
+
+<div id="t-usage">
+Download <a href="#" id="ur">usage records</a> (warning: may be slow!)
+<p>
+<label title="The name of a file to write usage records to. Note that this file will end up containing many XML documents concatenated together; it is up to you to split them up as necessary. Each record is only written as it is generated; this does not produce historic data." for="usageRecordDumpFile">Usage Record Dump File</label>
+<input title="The name of a file to write usage records to. Note that this file will end up containing many XML documents concatenated together; it is up to you to split them up as necessary. Each record is only written as it is generated; this does not produce historic data." id="usageRecordDumpFile" size="50" />
+</div><!-- t-usage -->
+
+<div id="t-worker">
+  <div id="a-worker">
+
+    <h3><a href="#">Subprocess Implementation Control</a></h3>
+    <div>
+      <table>
+	<tr>
+	  <td> <label title="The full path of the Java executable to use. Normally set correct by default." for="javaBinary">Java Executable (for subprocesses):</label> </td>
+	  <td> <input title="The full path of the Java executable to use. Normally set correct by default." id="javaBinary" size="80" /> </td>
+	</tr>
+	<tr>
+	  <td> <label title="The full path of the secure subprocess fork engine to use. Normally set correct by default." for="serverForkerJar">Subprocess Factory JAR:</label> </td>
+	  <td> <input title="The full path of the secure subprocess fork engine to use. Normally set correct by default." id="serverForkerJar" size="80" /> </td>
+	</tr>
+	<tr>
+	  <td> <label title="The full path of a file containing the credentials to use with sudo. Leave blank to use a password-less connection (see documentation for how to configure)." for="runasPasswordFile">File with password for sudo:</label> </td>
+	  <td> <input title="The full path of a file containing the credentials to use with sudo. Leave blank to use a password-less connection (see documentation for how to configure)." id="runasPasswordFile" size="80" /> </td>
+	</tr>
+	<tr>
+	  <td> <label title="The full path of the user filesystem access and workflow initiation engine to use. Normally set correct by default." for="serverWorkerJar">User Filesystem Access JAR:</label> </td>
+	  <td> <input title="The full path of the user filesystem access and workflow initiation engine to use. Normally set correct by default." id="serverWorkerJar" size="80" /> </td>
+	</tr>
+	<tr>
+	  <td> <label title="The full path of the workflow engine executable. Normally set correctly by default." for="executeWorkflowScript">Workflow Engine Executable:</label> </td>
+	  <td> <input title="The full path of the workflow engine executable. Normally set correctly by default." id="executeWorkflowScript" size="80" /> </td>
+	</tr>
+      </table>
+    </div>
+
+    <h3><a href="#">Worker Registration Control</a></h3>
+    <div>
+      <label title="The machine hosting the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryHost">Registry Host</label>
+      <input title="The machine hosting the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryHost" size="20" />
+      <label title="The port number the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryPort">Port</label>
+      <input title="The port number the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryPort" size="5" />
+      <br>
+      <label title="The full path of the RMI registry implementation JAR file. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryJar">RMI Registry JAR</label>
+      <input title="The full path of the RMI registry implementation JAR file. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryJar" size="80" />
+      <br>
+      <label title="The time to wait (in seconds) for the back-end processes to boot and register themselves with the RMI registry. Busy machines may need a longer value here." for="registrationWaitSeconds">Time to wait for registration (seconds)</label>
+      <input title="The time to wait (in seconds) for the back-end processes to boot and register themselves with the RMI registry. Busy machines may need a longer value here." id="registrationWaitSeconds" size="5" />
+      <br>
+      <label title="How long to wait (in milliseconds) between probes to the registry to detect the registration of a back-end process." for="registrationPollMillis">Time to wait between polling to
+      detect registration (milliseconds)</label>
+      <input title="How long to wait (in milliseconds) between probes to the registry to detect the registration of a back-end process." id="registrationPollMillis" size="5" />
+    </div>
+
+    <h3><a href="#">System User/Factory ID Mapping</a></h3>
+    <div>
+      <table title="The mapping of system user IDs to factory identifiers (used in the RMI registry). Note that this is read-only." id="factoryProcessMapping" border="1">
+      </table>
+    </div>
+
+   	<h3><a href="#">Extra Workflow Engine Configuration</a></h3>
+   	<div>
+   		<h4>System Properties</h4>
+   		<table id="extraArguments-prop">
+   		<tr><td></td><td><button title="Add a system property to pass to the back-end engine." id="extra-prop-add">Add System Property</button></td></tr>
+   		</table>
+   		<h4>Environment Variables</h4>
+   		<table id="extraArguments-env">
+   		<tr><td></td><td><button title="Add an environment variable to pass to the back-end engine." id="extra-env-add">Add Environment Variable</button></td></tr>
+   		</table>
+   		<h4>Java Runtime Configuration</h4>
+   		<table id="extraArguments-runtime">
+   		<tr><td></td><td><button title="Add a Java runtime parameter (e.g., Xmx=400m to set the memory usage limit to 400MB) to pass to the back-end engine. Note the lack of a leading '-' character!" id="extra-run-add">Add Runtime Configuration</button></td></tr>
+   		</table>
+   	</div>
+
+  </div><!-- a-worker -->
+</div><!-- t-worker -->
+
+</div>
+
+<hr>
+<address>Donal Fellows / University of Manchester</address>
+
+<!-- DIALOG BOXES -->
+<div id="dialog-confirm" title="Delete user?" style="display: none">
+  <p>
+  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
+  This user will be permanently deleted from the system. Are you sure?
+  </p>
+</div>
+
+<div id="dialog-password" title="Change password?" style="display: none">
+  <p>
+  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
+  This will permanently change the user's password. Make sure you wish
+  to do this.
+  </p>
+  <p>
+  <input title="New password" id="change-password" type="password" size="12" />
+  <br>
+  Please repeat it to be sure...
+  <br>
+  <input title="New password (again)" id="change-password2" type="password" size="12" />
+  </p>
+</div>
+
+<div id="dialog-environment" title="Set environment variable?" style="display: none">
+  <p>
+  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
+  Set an environment variable to be passed to the workflow engine.
+  </p>
+  <p>
+  <input title="Environment variable name" id="env-key" size="15" /> =
+  <input title="Environment variable value" id="env-value" size="20" />
+  </p>
+</div>
+
+<div id="dialog-runtime" title="Set runtime configuration?" style="display: none">
+  <p>
+  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
+  Set a runtime parameter (e.g., -Xmx400m for a 400MB memory limit) for the Java runtime.
+  </p>
+  <p>
+  <input title="Java runtime configuration parameter" id="runtime-value" size="20" />
+  </p>
+</div>
+
+<div id="dialog-property" title="Set runtime property?" style="display: none">
+  <p>
+  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
+  Set a configuration property for the Java runtime.
+  </p>
+  <p>
+  <input title="System property name" id="prop-key" size="15" /> =
+  <input title="System property value" id="prop-value" size="20" />
+  </p>
+</div>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/capabilities.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/capabilities.properties b/taverna-server-webapp/src/main/resources/capabilities.properties
new file mode 100644
index 0000000..2b4844f
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/capabilities.properties
@@ -0,0 +1,38 @@
+# This is currently a hand-curated list. This sucks! 
+
+######## --- PLATFORM --- ########
+http\://ns.taverna.org.uk/2013/software/taverna = 2.5
+
+######## --- OUTPUTS/PROVENANCE --- ########
+http\://ns.taverna.org.uk/2013/bundle/run = 1.0
+http\://ns.taverna.org.uk/2013/provenance/prov = 1.0
+
+######## --- ACTIVITIES --- ########
+http\://ns.taverna.org.uk/2010/activity/nested-workflow = 1.5
+http\://ns.taverna.org.uk/2010/activity/apiconsumer = 1.5
+http\://ns.taverna.org.uk/2010/activity/beanshell = 1.5
+http\://ns.taverna.org.uk/2010/activity/localworker = 1.5
+http\://ns.taverna.org.uk/2010/activity/biomart = 1.5
+http\://ns.taverna.org.uk/2010/activity/biomoby/object = 1.5
+http\://ns.taverna.org.uk/2010/activity/biomoby/service = 1.5
+http\://ns.taverna.org.uk/2010/activity/rshell = 1.5
+http\://ns.taverna.org.uk/2010/activity/soaplab = 1.5
+http\://ns.taverna.org.uk/2010/activity/spreadsheet-import = 1.5
+http\://ns.taverna.org.uk/2010/activity/constant = 1.5
+http\://ns.taverna.org.uk/2010/activity/component = 1.5
+http\://ns.taverna.org.uk/2010/activity/wsdl = 1.5
+http\://ns.taverna.org.uk/2010/activity/wsdl/xml-splitter/in = 1.5
+http\://ns.taverna.org.uk/2010/activity/wsdl/xml-splitter/out = 1.5
+http\://ns.taverna.org.uk/2010/activity/tool = 1.5
+http\://ns.taverna.org.uk/2010/activity/rest = 1.5
+http\://ns.taverna.org.uk/2010/activity/xpath = 1.5
+http\://ns.taverna.org.uk/2010/activity/webdav = 1.5
+http\://ns.taverna.org.uk/2010/activity/interaction = 1.5
+
+######## --- DISPATCH LAYERS --- ########
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/ErrorBounce = 1.5
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Failover = 1.5
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Invoke = 1.5
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Loop = 1.5
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Parallelize = 1.5
+http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Retry = 1.5
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/log4j.properties b/taverna-server-webapp/src/main/resources/log4j.properties
new file mode 100644
index 0000000..ea0ea12
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/log4j.properties
@@ -0,0 +1,39 @@
+log4j.rootLogger=info, R
+log4j.category.DataNucleus.Query=warn
+#log4j.category.DataNucleus.Datastore.Schema=debug
+#log4j.logger.org.springframework.security=DEBUG
+#log4j.category.Taverna=debug
+
+log4j.appender.R=org.apache.log4j.RollingFileAppender
+log4j.appender.R.File=${catalina.home}/logs/tavserv.out
+log4j.appender.R.MaxFileSize=10MB
+log4j.appender.R.MaxBackupIndex=30
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
+
+#log4j.category.Taverna=INFO, A1
+#log4j.category.Taverna.Server.LocalWorker.RunDB=INFO
+#log4j.category.Taverna.Server.Webapp=INFO
+#log4j.category.Taverna.Server.LocalWorker.Policy=INFO
+#log4j.category.Taverna.Server.LocalWorker.Security=INFO
+## Swallow Derby's messages
+#log4j.category.Derby=WARN, B2
+## Will you _shut up_, DataNucleus! <hits with rolled-up newspaper>
+#log4j.category.DataNucleus=WARN, B2
+##log4j.category.DataNucleus.SchemaTool=DEBUG
+##log4j.category.DataNucleus.Datastore.Schema=DEBUG
+##log4j.category.DataNucleus.Datastore.Native=DEBUG
+##log4j.logger.org.springframework.security=DEBUG, B2
+#log4j.category.org.springframework=INFO, B2
+#log4j.category.org.apache.cxf=INFO, B2
+#log4j.category.org.apache.cxf.jaxrs.utils.JAXRSUtils=INFO
+#log4j.category.eu.medsea=INFO, B2
+#log4j.category.org.apache.axiom=INFO, B2
+## Appender for Taverna Server components
+#log4j.appender.A1=org.apache.log4j.ConsoleAppender
+#log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+#log4j.appender.A1.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
+## Appender for Framework components
+#log4j.appender.B2=org.apache.log4j.ConsoleAppender
+#log4j.appender.B2.layout=org.apache.log4j.PatternLayout
+#log4j.appender.B2.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} - %m%n

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/security.policy
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/security.policy b/taverna-server-webapp/src/main/resources/security.policy
new file mode 100644
index 0000000..1ec4166
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/security.policy
@@ -0,0 +1,3 @@
+grant {
+   permission java.security.AllPermission "*:*";
+};


[25/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
deleted file mode 100644
index adf3ea7..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/LocalWorker.java
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.getProperty;
-import static java.lang.System.out;
-import static java.lang.management.ManagementFactory.getRuntimeMXBean;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singletonList;
-import static java.util.UUID.randomUUID;
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.forceMkdir;
-import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
-import static org.apache.commons.io.FileUtils.writeLines;
-import static org.taverna.server.localworker.api.Constants.HELIO_TOKEN_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_FILE;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.SECURITY_DIR_NAME;
-import static org.taverna.server.localworker.api.Constants.SHARED_DIR_PROP;
-import static org.taverna.server.localworker.api.Constants.SUBDIR_LIST;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TRUSTSTORE_FILE;
-import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedFile;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * This class implements one side of the connection between the Taverna Server
- * master server and this process. It delegates to a {@link Worker} instance the
- * handling of actually running a workflow.
- * 
- * @author Donal Fellows
- * @see DirectoryDelegate
- * @see FileDelegate
- * @see WorkerCore
- */
-@SuppressWarnings("serial")
-public class LocalWorker extends UnicastRemoteObject implements RemoteSingleRun {
-	// ----------------------- CONSTANTS -----------------------
-
-	/** Handle to the directory containing the security info. */
-	static final File SECURITY_DIR;
-	static final String SLASHTEMP;
-	static {
-		SLASHTEMP = getProperty("java.io.tmpdir");
-		File home = new File(getProperty("user.home"));
-		// If we can't write to $HOME (i.e., we're in an odd deployment) use
-		// the official version of /tmp/$PID as a fallback.
-		if (!home.canWrite())
-			home = new File(SLASHTEMP, getRuntimeMXBean().getName());
-		SECURITY_DIR = new File(home, SECURITY_DIR_NAME);
-	}
-
-	// ----------------------- VARIABLES -----------------------
-
-	/**
-	 * Magic flag used to turn off problematic code when testing inside CI
-	 * environment.
-	 */
-	static boolean DO_MKDIR = true;
-
-	/** What to use to run a workflow engine. */
-	private final String executeWorkflowCommand;
-	/** What workflow to run. */
-	private final byte[] workflow;
-	/** The remote access object for the working directory. */
-	private final DirectoryDelegate baseDir;
-	/** What inputs to pass as files. */
-	final Map<String, String> inputFiles;
-	/** What inputs to pass as files (as file refs). */
-	final Map<String, File> inputRealFiles;
-	/** What inputs to pass as direct values. */
-	final Map<String, String> inputValues;
-	/** What delimiters to use. */
-	final Map<String, String> inputDelimiters;
-	/** The interface to the workflow engine subprocess. */
-	private final Worker core;
-	/** Our descriptor token (UUID). */
-	private final String masterToken;
-	/**
-	 * The root working directory for a workflow run, or <tt>null</tt> if it has
-	 * been deleted.
-	 */
-	private File base;
-	/**
-	 * When did this workflow start running, or <tt>null</tt> for
-	 * "never/not yet".
-	 */
-	private Date start;
-	/**
-	 * When did this workflow finish running, or <tt>null</tt> for
-	 * "never/not yet".
-	 */
-	private Date finish;
-	/** The cached status of the workflow run. */
-	RemoteStatus status;
-	/**
-	 * The name of the input Baclava document, or <tt>null</tt> to not do it
-	 * that way.
-	 */
-	String inputBaclava;
-	/**
-	 * The name of the output Baclava document, or <tt>null</tt> to not do it
-	 * that way.
-	 */
-	String outputBaclava;
-	/**
-	 * The file containing the input Baclava document, or <tt>null</tt> to not
-	 * do it that way.
-	 */
-	private File inputBaclavaFile;
-	/**
-	 * The file containing the output Baclava document, or <tt>null</tt> to not
-	 * do it that way.
-	 */
-	private File outputBaclavaFile;
-	/**
-	 * Registered shutdown hook so that we clean up when this process is killed
-	 * off, or <tt>null</tt> if that is no longer necessary.
-	 */
-	Thread shutdownHook;
-	/** Location for security information to be written to. */
-	File securityDirectory;
-	/**
-	 * Password to use to encrypt security information.
-	 */
-	char[] keystorePassword = KEYSTORE_PASSWORD;
-	/** Additional server-specified environment settings. */
-	Map<String, String> environment = new HashMap<>();
-	/** Additional server-specified java runtime settings. */
-	List<String> runtimeSettings = new ArrayList<>();
-	URL interactionFeedURL;
-	URL webdavURL;
-	URL publishURL;//FIXME
-	private boolean doProvenance = true;
-
-	// ----------------------- METHODS -----------------------
-
-	/**
-	 * @param executeWorkflowCommand
-	 *            The script used to execute workflows.
-	 * @param workflow
-	 *            The workflow to execute.
-	 * @param workerClass
-	 *            The class to instantiate as our local representative of the
-	 *            run.
-	 * @param urReceiver
-	 *            The remote class to report the generated usage record(s) to.
-	 * @param id
-	 *            The UUID to use, or <tt>null</tt> if we are to invent one.
-	 * @param seedEnvironment
-	 *            The key/value pairs to seed the worker subprocess environment
-	 *            with.
-	 * @param javaParams
-	 *            Parameters to pass to the worker subprocess java runtime
-	 *            itself.
-	 * @param workerFactory
-	 *            How to make instances of the low-level worker objects.
-	 * @throws RemoteException
-	 *             If registration of the worker fails.
-	 * @throws ImplementationException
-	 *             If something goes wrong during local setup.
-	 */
-	protected LocalWorker(String executeWorkflowCommand, byte[] workflow,
-			UsageRecordReceiver urReceiver, UUID id,
-			Map<String, String> seedEnvironment, List<String> javaParams,
-			WorkerFactory workerFactory) throws RemoteException,
-			ImplementationException {
-		super();
-		if (id == null)
-			id = randomUUID();
-		masterToken = id.toString();
-		this.workflow = workflow;
-		this.executeWorkflowCommand = executeWorkflowCommand;
-		String sharedDir = getProperty(SHARED_DIR_PROP, SLASHTEMP);
-		base = new File(sharedDir, masterToken);
-		out.println("about to create " + base);
-		try {
-			forceMkdir(base);
-			for (String subdir : SUBDIR_LIST) {
-				new File(base, subdir).mkdir();
-			}
-		} catch (IOException e) {
-			throw new ImplementationException(
-					"problem creating run working directory", e);
-		}
-		baseDir = new DirectoryDelegate(base, null);
-		inputFiles = new HashMap<>();
-		inputRealFiles = new HashMap<>();
-		inputValues = new HashMap<>();
-		inputDelimiters = new HashMap<>();
-		environment.putAll(seedEnvironment);
-		runtimeSettings.addAll(javaParams);
-		try {
-			core = workerFactory.makeInstance();
-		} catch (Exception e) {
-			out.println("problem when creating core worker implementation");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem when creating core worker implementation", e);
-		}
-		core.setURReceiver(urReceiver);
-		Thread t = new Thread(new Runnable() {
-			/**
-			 * Kill off the worker launched by the core.
-			 */
-			@Override
-			public void run() {
-				try {
-					shutdownHook = null;
-					destroy();
-				} catch (ImplementationException e) {
-					// Absolutely nothing we can do here
-				}
-			}
-		});
-		getRuntime().addShutdownHook(t);
-		shutdownHook = t;
-		status = Initialized;
-	}
-
-	@Override
-	public void destroy() throws ImplementationException {
-		killWorkflowSubprocess();
-		removeFromShutdownHooks();
-		// Is this it?
-		deleteWorkingDirectory();
-		deleteSecurityManagerDirectory();
-		core.deleteLocalResources();
-	}
-
-	private void killWorkflowSubprocess() {
-		if (status != Finished && status != Initialized)
-			try {
-				core.killWorker();
-				if (finish == null)
-					finish = new Date();
-			} catch (Exception e) {
-				out.println("problem when killing worker");
-				e.printStackTrace(out);
-			}
-	}
-
-	private void removeFromShutdownHooks() throws ImplementationException {
-		try {
-			if (shutdownHook != null)
-				getRuntime().removeShutdownHook(shutdownHook);
-		} catch (RuntimeException e) {
-			throw new ImplementationException("problem removing shutdownHook",
-					e);
-		} finally {
-			shutdownHook = null;
-		}
-	}
-
-	private void deleteWorkingDirectory() throws ImplementationException {
-		try {
-			if (base != null)
-				forceDelete(base);
-		} catch (IOException e) {
-			out.println("problem deleting working directory");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem deleting working directory", e);
-		} finally {
-			base = null;
-		}
-	}
-
-	private void deleteSecurityManagerDirectory()
-			throws ImplementationException {
-		try {
-			if (securityDirectory != null)
-				forceDelete(securityDirectory);
-		} catch (IOException e) {
-			out.println("problem deleting security directory");
-			e.printStackTrace(out);
-			throw new ImplementationException(
-					"problem deleting security directory", e);
-		} finally {
-			securityDirectory = null;
-		}
-	}
-
-	@Override
-	public void addListener(RemoteListener listener) throws RemoteException,
-			ImplementationException {
-		throw new ImplementationException("not implemented");
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		return inputBaclava;
-	}
-
-	@Override
-	public List<RemoteInput> getInputs() throws RemoteException {
-		ArrayList<RemoteInput> result = new ArrayList<>();
-		for (String name : inputFiles.keySet())
-			result.add(new InputDelegate(name));
-		return result;
-	}
-
-	@Override
-	public List<String> getListenerTypes() {
-		return emptyList();
-	}
-
-	@Override
-	public List<RemoteListener> getListeners() {
-		return singletonList(core.getDefaultListener());
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		return outputBaclava;
-	}
-
-	class SecurityDelegate extends UnicastRemoteObject implements
-			RemoteSecurityContext {
-		private void setPrivatePerms(File dir) {
-			if (!dir.setReadable(false, false) || !dir.setReadable(true, true)
-					|| !dir.setExecutable(false, false)
-					|| !dir.setExecutable(true, true)
-					|| !dir.setWritable(false, false)
-					|| !dir.setWritable(true, true)) {
-				out.println("warning: "
-						+ "failed to set permissions on security context directory");
-			}
-		}
-
-		protected SecurityDelegate(String token) throws IOException {
-			super();
-			if (DO_MKDIR) {
-				securityDirectory = new File(SECURITY_DIR, token);
-				forceMkdir(securityDirectory);
-				setPrivatePerms(securityDirectory);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The bytes to put in the file.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, byte[] data) throws RemoteException,
-				ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeByteArrayToFile(f, data);
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The lines to put in the file. The
-		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
-		 *            will be used to do the writing.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, Collection<String> data)
-				throws RemoteException, ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeLines(f, SYSTEM_ENCODING, data);
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		/**
-		 * Write some data to a given file in the context directory.
-		 * 
-		 * @param name
-		 *            The name of the file to write.
-		 * @param data
-		 *            The line to put in the file. The
-		 *            {@linkplain LocalWorker#SYSTEM_ENCODING system encoding}
-		 *            will be used to do the writing.
-		 * @throws RemoteException
-		 *             If anything goes wrong.
-		 * @throws ImplementationException
-		 */
-		protected void write(String name, char[] data) throws RemoteException,
-				ImplementationException {
-			try {
-				File f = new File(securityDirectory, name);
-				writeLines(f, SYSTEM_ENCODING, asList(new String(data)));
-			} catch (IOException e) {
-				throw new ImplementationException("problem writing " + name, e);
-			}
-		}
-
-		@Override
-		public void setKeystore(byte[] keystore) throws RemoteException,
-				ImplementationException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (keystore == null)
-				throw new IllegalArgumentException("keystore may not be null");
-			write(KEYSTORE_FILE, keystore);
-		}
-
-		@Override
-		public void setPassword(char[] password) throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (password == null)
-				throw new IllegalArgumentException("password may not be null");
-			keystorePassword = password.clone();
-		}
-
-		@Override
-		public void setTruststore(byte[] truststore) throws RemoteException,
-				ImplementationException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (truststore == null)
-				throw new IllegalArgumentException("truststore may not be null");
-			write(TRUSTSTORE_FILE, truststore);
-		}
-
-		@Override
-		public void setUriToAliasMap(Map<URI, String> uriToAliasMap)
-				throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			if (uriToAliasMap == null)
-				return;
-			ArrayList<String> lines = new ArrayList<>();
-			for (Entry<URI, String> site : uriToAliasMap.entrySet())
-				lines.add(site.getKey().toASCIIString() + " " + site.getValue());
-			// write(URI_ALIAS_MAP, lines);
-		}
-
-		@Override
-		public void setHelioToken(String helioToken) throws RemoteException {
-			if (status != Initialized)
-				throw new RemoteException("not initializing");
-			out.println("registering HELIO CIS token for export");
-			environment.put(HELIO_TOKEN_NAME, helioToken);
-		}
-	}
-
-	@Override
-	public RemoteSecurityContext getSecurityContext() throws RemoteException,
-			ImplementationException {
-		try {
-			return new SecurityDelegate(masterToken);
-		} catch (RemoteException e) {
-			if (e.getCause() != null)
-				throw new ImplementationException(
-						"problem initializing security context", e.getCause());
-			throw e;
-		} catch (IOException e) {
-			throw new ImplementationException(
-					"problem initializing security context", e);
-		}
-	}
-
-	@Override
-	public RemoteStatus getStatus() {
-		// only state that can spontaneously change to another
-		if (status == Operating) {
-			status = core.getWorkerStatus();
-			if (status == Finished && finish == null)
-				finish = new Date();
-		}
-		return status;
-	}
-
-	@Override
-	public RemoteDirectory getWorkingDirectory() {
-		return baseDir;
-	}
-
-	File validateFilename(String filename) throws RemoteException {
-		if (filename == null)
-			throw new IllegalArgumentException("filename must be non-null");
-		try {
-			return getValidatedFile(base, filename.split("/"));
-		} catch (IOException e) {
-			throw new IllegalArgumentException("failed to validate filename", e);
-		}
-	}
-
-	class InputDelegate extends UnicastRemoteObject implements RemoteInput {
-		private String name;
-
-		InputDelegate(String name) throws RemoteException {
-			super();
-			this.name = name;
-			if (!inputFiles.containsKey(name)) {
-				if (status != Initialized)
-					throw new IllegalStateException("not initializing");
-				inputFiles.put(name, null);
-				inputRealFiles.put(name, null);
-				inputValues.put(name, null);
-				inputDelimiters.put(name, null);
-			}
-		}
-
-		@Override
-		public String getFile() {
-			return inputFiles.get(name);
-		}
-
-		@Override
-		public String getName() {
-			return name;
-		}
-
-		@Override
-		public String getValue() {
-			return inputValues.get(name);
-		}
-
-		@Override
-		public String getDelimiter() throws RemoteException {
-			return inputDelimiters.get(name);
-		}
-
-		@Override
-		public void setFile(String file) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			inputRealFiles.put(name, validateFilename(file));
-			inputValues.put(name, null);
-			inputFiles.put(name, file);
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setValue(String value) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			inputValues.put(name, value);
-			inputFiles.put(name, null);
-			inputRealFiles.put(name, null);
-			inputBaclava = null;
-		}
-
-		@Override
-		public void setDelimiter(String delimiter) throws RemoteException {
-			if (status != Initialized)
-				throw new IllegalStateException("not initializing");
-			if (inputBaclava != null)
-				throw new IllegalStateException("input baclava file set");
-			if (delimiter != null) {
-				if (delimiter.length() > 1)
-					throw new IllegalStateException(
-							"multi-character delimiter not permitted");
-				if (delimiter.charAt(0) == 0)
-					throw new IllegalStateException(
-							"may not use NUL for splitting");
-				if (delimiter.charAt(0) > 127)
-					throw new IllegalStateException(
-							"only ASCII characters supported for splitting");
-			}
-			inputDelimiters.put(name, delimiter);
-		}
-	}
-
-	@Override
-	public RemoteInput makeInput(String name) throws RemoteException {
-		return new InputDelegate(name);
-	}
-
-	@Override
-	public RemoteListener makeListener(String type, String configuration)
-			throws RemoteException {
-		throw new RemoteException("listener manufacturing unsupported");
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename) throws RemoteException {
-		if (status != Initialized)
-			throw new IllegalStateException("not initializing");
-		inputBaclavaFile = validateFilename(filename);
-		for (String input : inputFiles.keySet()) {
-			inputFiles.put(input, null);
-			inputRealFiles.put(input, null);
-			inputValues.put(input, null);
-		}
-		inputBaclava = filename;
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename) throws RemoteException {
-		if (status != Initialized)
-			throw new IllegalStateException("not initializing");
-		if (filename != null)
-			outputBaclavaFile = validateFilename(filename);
-		else
-			outputBaclavaFile = null;
-		outputBaclava = filename;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean prov) {
-		doProvenance = prov;
-	}
-
-	@Override
-	public void setStatus(RemoteStatus newStatus)
-			throws IllegalStateTransitionException, RemoteException,
-			ImplementationException, StillWorkingOnItException {
-		if (status == newStatus)
-			return;
-
-		switch (newStatus) {
-		case Initialized:
-			throw new IllegalStateTransitionException(
-					"may not move back to start");
-		case Operating:
-			switch (status) {
-			case Initialized:
-				boolean started;
-				try {
-					started = createWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem creating executing workflow", e);
-				}
-				if (!started)
-					throw new StillWorkingOnItException(
-							"workflow start in process");
-				break;
-			case Stopped:
-				try {
-					core.startWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem continuing workflow run", e);
-				}
-				break;
-			case Finished:
-				throw new IllegalStateTransitionException("already finished");
-			default:
-				break;
-			}
-			status = Operating;
-			break;
-		case Stopped:
-			switch (status) {
-			case Initialized:
-				throw new IllegalStateTransitionException(
-						"may only stop from Operating");
-			case Operating:
-				try {
-					core.stopWorker();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem stopping workflow run", e);
-				}
-				break;
-			case Finished:
-				throw new IllegalStateTransitionException("already finished");
-			default:
-				break;
-			}
-			status = Stopped;
-			break;
-		case Finished:
-			switch (status) {
-			case Operating:
-			case Stopped:
-				try {
-					core.killWorker();
-					if (finish == null)
-						finish = new Date();
-				} catch (Exception e) {
-					throw new ImplementationException(
-							"problem killing workflow run", e);
-				}
-			default:
-				break;
-			}
-			status = Finished;
-			break;
-		}
-	}
-
-	private boolean createWorker() throws Exception {
-		start = new Date();
-		char[] pw = keystorePassword;
-		keystorePassword = null;
-		/*
-		 * Do not clear the keystorePassword array here; its ownership is
-		 * *transferred* to the worker core which doesn't copy it but *does*
-		 * clear it after use.
-		 */
-		return core.initWorker(this, executeWorkflowCommand, workflow, base,
-				inputBaclavaFile, inputRealFiles, inputValues, inputDelimiters,
-				outputBaclavaFile, securityDirectory, pw, doProvenance,
-				environment, masterToken, runtimeSettings);
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		return finish == null ? null : new Date(finish.getTime());
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		return start == null ? null : new Date(start.getTime());
-	}
-
-	@Override
-	public void setInteractionServiceDetails(URL feed, URL webdav, URL publish) {
-		interactionFeedURL = feed;
-		webdavURL = webdav;
-		publishURL = publish;
-	}
-
-	@Override
-	public void ping() {
-		// Do nothing here; this *should* be empty
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
deleted file mode 100644
index 03ee69d..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/TavernaRunManager.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.exit;
-import static java.lang.System.getProperty;
-import static java.lang.System.out;
-import static java.lang.System.setProperty;
-import static java.lang.System.setSecurityManager;
-import static java.rmi.registry.LocateRegistry.getRegistry;
-import static org.taverna.server.localworker.api.Constants.DEATH_DELAY;
-import static org.taverna.server.localworker.api.Constants.LOCALHOST;
-import static org.taverna.server.localworker.api.Constants.RMI_HOST_PROP;
-import static org.taverna.server.localworker.api.Constants.SECURITY_POLICY_FILE;
-import static org.taverna.server.localworker.api.Constants.SEC_POLICY_PROP;
-import static org.taverna.server.localworker.api.Constants.UNSECURE_PROP;
-
-import java.io.ByteArrayInputStream;
-import java.net.URI;
-import java.rmi.RMISecurityManager;
-import java.rmi.RemoteException;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.RemoteRunFactory;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
-
-/**
- * The registered factory for runs, this class is responsible for constructing
- * runs that are suitable for particular users. It is also the entry point for
- * this whole process.
- * 
- * @author Donal Fellows
- * @see LocalWorker
- */
-@SuppressWarnings("serial")
-public class TavernaRunManager extends UnicastRemoteObject implements
-		RemoteRunFactory, RunAccounting, WorkerFactory {
-	String command;
-	Map<String, String> seedEnvironment = new HashMap<>();
-	List<String> javaInitParams = new ArrayList<>();
-	private WorkflowBundleIO io;
-	private int activeRuns = 0;
-	// Hacks!
-	public static String interactionHost;
-	public static String interactionPort;
-	public static String interactionWebdavPath;
-	public static String interactionFeedPath;
-
-	/**
-	 * How to get the actual workflow document from the XML document that it is
-	 * contained in.
-	 * 
-	 * @param containerDocument
-	 *            The document sent from the web interface.
-	 * @return The element describing the workflow, as expected by the Taverna
-	 *         command line executor.
-	 */
-	protected Element unwrapWorkflow(Document containerDocument) {
-		return (Element) containerDocument.getDocumentElement().getFirstChild();
-	}
-
-	private static final String usage = "java -jar server.worker.jar workflowExecScript ?-Ekey=val...? ?-Jconfig? UUID";
-
-	/**
-	 * An RMI-enabled factory for runs.
-	 * 
-	 * @param command
-	 *            What command to call to actually run a run.
-	 * @throws RemoteException
-	 *             If anything goes wrong during creation of the instance.
-	 */
-	public TavernaRunManager(String command) throws RemoteException {
-		this.command = command;
-		this.io = new WorkflowBundleIO();
-	}
-
-	@Override
-	public RemoteSingleRun make(byte[] workflow, String creator,
-			UsageRecordReceiver urReceiver, UUID id) throws RemoteException {
-		if (creator == null)
-			throw new RemoteException("no creator");
-		try {
-			URI wfid = io.readBundle(new ByteArrayInputStream(workflow), null)
-					.getMainWorkflow().getWorkflowIdentifier();
-			out.println("Creating run from workflow <" + wfid + "> for <"
-					+ creator + ">");
-			return new LocalWorker(command, workflow, urReceiver, id,
-					seedEnvironment, javaInitParams, this);
-		} catch (RemoteException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new RemoteException("bad instance construction", e);
-		}
-	}
-
-	private static boolean shuttingDown;
-	private static String factoryName;
-	private static Registry registry;
-
-	static synchronized void unregisterFactory() {
-		if (!shuttingDown) {
-			shuttingDown = true;
-			try {
-				if (factoryName != null && registry != null)
-					registry.unbind(factoryName);
-			} catch (Exception e) {
-				e.printStackTrace(out);
-			}
-		}
-	}
-
-	@Override
-	public void shutdown() {
-		unregisterFactory();
-		new Thread(new DelayedDeath()).start();
-	}
-
-	static class DelayedDeath implements Runnable {
-		@Override
-		public void run() {
-			try {
-				Thread.sleep(DEATH_DELAY);
-			} catch (InterruptedException e) {
-			} finally {
-				exit(0);
-			}
-		}
-	}
-
-	private void addArgument(String arg) {
-		if (arg.startsWith("-E")) {
-			String trimmed = arg.substring(2);
-			int idx = trimmed.indexOf('=');
-			if (idx > 0) {
-				addEnvironmentDefinition(trimmed.substring(0, idx),
-						trimmed.substring(idx + 1));
-				return;
-			}
-		} else if (arg.startsWith("-D")) {
-			if (arg.indexOf('=') > 0) {
-				addJavaParameter(arg);
-				return;
-			}
-		} else if (arg.startsWith("-J")) {
-			addJavaParameter(arg.substring(2));
-			return;
-		}
-		throw new IllegalArgumentException("argument \"" + arg
-				+ "\" must start with -D, -E or -J; "
-				+ "-D and -E must contain a \"=\"");
-	}
-
-	/**
-	 * @param args
-	 *            The arguments from the command line invocation.
-	 * @throws Exception
-	 *             If we can't connect to the RMI registry, or if we can't read
-	 *             the workflow, or if we can't build the worker instance, or
-	 *             register it. Also if the arguments are wrong.
-	 */
-	public static void main(String[] args) throws Exception {
-		if (args.length < 2)
-			throw new Exception("wrong # args: must be \"" + usage + "\"");
-		if (!getProperty(UNSECURE_PROP, "no").equals("yes")) {
-			setProperty(SEC_POLICY_PROP, LocalWorker.class.getClassLoader()
-					.getResource(SECURITY_POLICY_FILE).toExternalForm());
-			setProperty(RMI_HOST_PROP, LOCALHOST);
-		}
-		setSecurityManager(new RMISecurityManager());
-		factoryName = args[args.length - 1];
-		TavernaRunManager man = new TavernaRunManager(args[0]);
-		for (int i = 1; i < args.length - 1; i++)
-			man.addArgument(args[i]);
-		registry = getRegistry(LOCALHOST);
-
-		registry.bind(factoryName, man);
-		getRuntime().addShutdownHook(new Thread() {
-			@Override
-			public void run() {
-				unregisterFactory();
-			}
-		});
-		out.println("registered RemoteRunFactory with ID " + factoryName);
-	}
-
-	private void addJavaParameter(String string) {
-		this.javaInitParams.add(string);
-	}
-
-	private void addEnvironmentDefinition(String key, String value) {
-		this.seedEnvironment.put(key, value);
-	}
-
-	@Override
-	public void setInteractionServiceDetails(String host, String port,
-			String webdavPath, String feedPath) throws RemoteException {
-		if (host == null || port == null || webdavPath == null
-				|| feedPath == null)
-			throw new IllegalArgumentException("all params must be non-null");
-		interactionHost = host;
-		interactionPort = port;
-		interactionWebdavPath = webdavPath;
-		interactionFeedPath = feedPath;
-	}
-
-	@Override
-	public synchronized int countOperatingRuns() {
-		return (activeRuns < 0 ? 0 : activeRuns);
-	}
-
-	@Override
-	public synchronized void runStarted() {
-		activeRuns++;
-	}
-
-	@Override
-	public synchronized void runCeased() {
-		activeRuns--;
-	}
-
-	@Override
-	public Worker makeInstance() throws Exception {
-		return new WorkerCore(this);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
deleted file mode 100644
index 1a6cff8..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/WorkerCore.java
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static java.io.File.createTempFile;
-import static java.io.File.pathSeparator;
-import static java.lang.Boolean.parseBoolean;
-import static java.lang.Double.parseDouble;
-import static java.lang.Integer.parseInt;
-import static java.lang.Long.parseLong;
-import static java.lang.Runtime.getRuntime;
-import static java.lang.System.out;
-import static java.net.InetAddress.getLocalHost;
-import static org.apache.commons.io.FileUtils.forceDelete;
-import static org.apache.commons.io.FileUtils.sizeOfDirectory;
-import static org.apache.commons.io.FileUtils.write;
-import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_DIRECTORY;
-import static org.taverna.server.localworker.api.Constants.CREDENTIAL_MANAGER_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.DEATH_TIME;
-import static org.taverna.server.localworker.api.Constants.DEFAULT_LISTENER_NAME;
-import static org.taverna.server.localworker.api.Constants.KEYSTORE_PASSWORD;
-import static org.taverna.server.localworker.api.Constants.START_WAIT_TIME;
-import static org.taverna.server.localworker.api.Constants.SYSTEM_ENCODING;
-import static org.taverna.server.localworker.api.Constants.TIME;
-import static org.taverna.server.localworker.impl.Status.Aborted;
-import static org.taverna.server.localworker.impl.Status.Completed;
-import static org.taverna.server.localworker.impl.Status.Failed;
-import static org.taverna.server.localworker.impl.Status.Held;
-import static org.taverna.server.localworker.impl.Status.Started;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionFeedPath;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionHost;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionPort;
-import static org.taverna.server.localworker.impl.TavernaRunManager.interactionWebdavPath;
-import static org.taverna.server.localworker.impl.WorkerCore.pmap;
-import static org.taverna.server.localworker.remote.RemoteStatus.Finished;
-import static org.taverna.server.localworker.remote.RemoteStatus.Initialized;
-import static org.taverna.server.localworker.remote.RemoteStatus.Operating;
-import static org.taverna.server.localworker.remote.RemoteStatus.Stopped;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.ws.Holder;
-
-import org.ogf.usage.JobUsageRecord;
-import org.taverna.server.localworker.api.RunAccounting;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.impl.utils.TimingOutTask;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-/**
- * The core class that connects to a Taverna command-line workflow execution
- * engine. This implementation always registers a single listener, &lquo;
- * <tt>io</tt> &rquo;, with two properties representing the stdout and stderr of
- * the run and one representing the exit code. The listener is
- * remote-accessible. It does not support attaching any other listeners.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class WorkerCore extends UnicastRemoteObject implements Worker,
-		RemoteListener {
-	@Nonnull
-	static final Map<String, Property> pmap = new HashMap<>();
-	/**
-	 * Regular expression to extract the detailed timing information from the
-	 * output of /usr/bin/time
-	 */
-	@Nonnull
-	private static final Pattern TimeRE;
-	static {
-		final String TIMERE = "([0-9.:]+)";
-		final String TERMS = "(real|user|system|sys|elapsed)";
-		TimeRE = Pattern.compile(TIMERE + " *" + TERMS + "[ \t]*" + TIMERE
-				+ " *" + TERMS + "[ \t]*" + TIMERE + " *" + TERMS);
-	}
-
-	/**
-	 * Environment variables to remove before any fork (because they're large or
-	 * potentially leaky).
-	 */
-	// TODO Conduct a proper survey of what to remove
-	@Nonnull
-	private static final String[] ENVIRONMENT_TO_REMOVE = { "SUDO_COMMAND",
-			"SUDO_USER", "SUDO_GID", "SUDO_UID", "DISPLAY", "LS_COLORS",
-			"XFILESEARCHPATH", "SSH_AGENT_PID", "SSH_AUTH_SOCK" };
-
-	@Nullable
-	Process subprocess;
-	@Nonnull
-	final StringWriter stdout;
-	@Nonnull
-	final StringWriter stderr;
-	@Nullable
-	Integer exitCode;
-	boolean readyToSendEmail;
-	@Nullable
-	String emailAddress;
-	@Nullable
-	Date start;
-	@Nonnull
-	final RunAccounting accounting;
-	@Nonnull
-	final Holder<Integer> pid;
-
-	private boolean finished;
-	@Nullable
-	private JobUsageRecord ur;
-	@Nullable
-	private File wd;
-	@Nullable
-	private UsageRecordReceiver urreceiver;
-	@Nullable
-	private File workflowFile;
-	private boolean stopped;
-
-	/**
-	 * @param accounting
-	 *            Object that looks after how many runs are executing.
-	 * @throws RemoteException
-	 */
-	public WorkerCore(@Nonnull RunAccounting accounting) throws RemoteException {
-		super();
-		stdout = new StringWriter();
-		stderr = new StringWriter();
-		pid = new Holder<>();
-		this.accounting = accounting;
-	}
-
-	private int getPID() {
-		synchronized (pid) {
-			if (pid.value == null)
-				return -1;
-			return pid.value;
-		}
-	}
-
-	/**
-	 * Fire up the workflow. This causes a transition into the operating state.
-	 * 
-	 * @param executeWorkflowCommand
-	 *            The command to run to execute the workflow.
-	 * @param workflow
-	 *            The workflow document to execute.
-	 * @param workingDir
-	 *            What directory to use as the working directory.
-	 * @param inputBaclava
-	 *            The baclava file to use for inputs, or <tt>null</tt> to use
-	 *            the other <b>input*</b> arguments' values.
-	 * @param inputFiles
-	 *            A mapping of input names to files that supply them. Note that
-	 *            we assume that nothing mapped here will be mapped in
-	 *            <b>inputValues</b>.
-	 * @param inputValues
-	 *            A mapping of input names to values to supply to them. Note
-	 *            that we assume that nothing mapped here will be mapped in
-	 *            <b>inputFiles</b>.
-	 * @param outputBaclava
-	 *            What baclava file to write the output from the workflow into,
-	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
-	 *            subdirectory.
-	 * @param token
-	 *            The name of the workflow run.
-	 * @return <tt>true</tt> if the worker started, or <tt>false</tt> if a
-	 *         timeout occurred.
-	 * @throws IOException
-	 *             If any of quite a large number of things goes wrong.
-	 */
-	@Override
-	public boolean initWorker(
-			@Nonnull final LocalWorker local,
-			@Nonnull final String executeWorkflowCommand,
-			@Nonnull final byte[] workflow,
-			@Nonnull final File workingDir,
-			@Nullable final File inputBaclava,
-			@Nonnull final Map<String, File> inputFiles,
-			@Nonnull final Map<String, String> inputValues, 
-			@Nonnull final Map<String, String> inputDelimiters,
-			@Nullable final File outputBaclava,
-			@Nonnull final File securityDir,
-			@Nullable final char[] password,
-			final boolean generateProvenance,
-			@Nonnull final Map<String, String> environment,
-			@Nullable final String token,
-			@Nonnull final List<String> runtime) throws IOException {
-		try {
-			new TimingOutTask() {
-				@Override
-				public void doIt() throws IOException {
-					startExecutorSubprocess(
-							createProcessBuilder(local, executeWorkflowCommand,
-									workflow, workingDir, inputBaclava,
-									inputFiles, inputValues, inputDelimiters,
-									outputBaclava, securityDir, password,
-									generateProvenance, environment, token,
-									runtime), password);
-				}
-			}.doOrTimeOut(START_WAIT_TIME);
-		} catch (IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new IOException(e);
-		}
-		return subprocess != null;
-	}
-
-	private void startExecutorSubprocess(@Nonnull ProcessBuilder pb,
-			@Nullable char[] password) throws IOException {
-		// Start the subprocess
-		out.println("starting " + pb.command() + " in directory "
-				+ pb.directory() + " with environment " + pb.environment());
-		subprocess = pb.start();
-		if (subprocess == null)
-			throw new IOException("unknown failure creating process");
-		start = new Date();
-		accounting.runStarted();
-
-		// Capture its stdout and stderr
-		new AsyncCopy(subprocess.getInputStream(), stdout, pid);
-		new AsyncCopy(subprocess.getErrorStream(), stderr);
-		if (password != null)
-			new PasswordWriterThread(subprocess, password);
-	}
-
-	/**
-	 * Assemble the process builder. Does not launch the subprocess.
-	 * 
-	 * @param local
-	 *            The local worker container.
-	 * @param executeWorkflowCommand
-	 *            The reference to the workflow engine implementation.
-	 * @param workflow
-	 *            The workflow to execute.
-	 * @param workingDir
-	 *            The working directory to use.
-	 * @param inputBaclava
-	 *            What file to read a baclava document from (or <tt>null</tt>)
-	 * @param inputFiles
-	 *            The mapping from inputs to files.
-	 * @param inputValues
-	 *            The mapping from inputs to literal values.
-	 * @param outputBaclava
-	 *            What file to write a baclava document to (or <tt>null</tt>)
-	 * @param securityDir
-	 *            The credential manager directory.
-	 * @param password
-	 *            The password for the credential manager.
-	 * @param environment
-	 *            The seed environment
-	 * @param token
-	 *            The run identifier that the server wants to use.
-	 * @param runtime
-	 *            Any runtime parameters to Java.
-	 * @return The configured process builder.
-	 * @throws IOException
-	 *             If file handling fails
-	 * @throws UnsupportedEncodingException
-	 *             If we can't encode any text (unlikely)
-	 * @throws FileNotFoundException
-	 *             If we can't write the workflow out (unlikely)
-	 */
-	@Nonnull
-	ProcessBuilder createProcessBuilder(@Nonnull LocalWorker local,
-			@Nonnull String executeWorkflowCommand, @Nonnull byte[] workflow,
-			@Nonnull File workingDir, @Nullable File inputBaclava,
-			@Nonnull Map<String, File> inputFiles,
-			@Nonnull Map<String, String> inputValues,
-			@Nonnull Map<String, String> inputDelimiters,
-			@Nullable File outputBaclava, @Nonnull File securityDir,
-			@Nonnull char[] password, boolean generateProvenance,
-			@Nonnull Map<String, String> environment, @Nonnull String token,
-			@Nonnull List<String> runtime) throws IOException,
-			UnsupportedEncodingException, FileNotFoundException {
-		ProcessBuilder pb = new ProcessBuilder();
-		pb.command().add(TIME);
-		/*
-		 * WARNING! HERE THERE BE DRAGONS! BE CAREFUL HERE!
-		 * 
-		 * Work around _Maven_ bug with permissions in zip files! The executable
-		 * bit is stripped by Maven's handling of file permissions, and there's
-		 * no practical way to work around it without massively increasing the
-		 * pain in other ways. Only want this on Unix - Windows isn't affected
-		 * by this - so we use the file separator as a proxy for whether this is
-		 * a true POSIX system. Ugly! Ugly ugly ugly...
-		 * 
-		 * http://jira.codehaus.org/browse/MASSEMBLY-337 is relevant, but not
-		 * the whole story as we don't want to use a non-standard packaging
-		 * method as there's a real chance of it going wrong in an unexpected
-		 * way then. Other parts of the story are that the executable bit isn't
-		 * preserved when unpacking with the dependency plugin, and there's no
-		 * way to be sure that the servlet container will preserve the bit
-		 * either (as that's probably using a Java-based ZIP engine).
-		 */
-		if (File.separatorChar == '/')
-			pb.command().add("/bin/sh");
-		pb.command().add(executeWorkflowCommand);
-		if (runtime != null)
-			pb.command().addAll(runtime);
-
-		// Enable verbose logging
-		pb.command().add("-logfile");
-		pb.command().add(
-				new File(new File(workingDir, "logs"), "detail.log")
-						.getAbsolutePath());
-
-		if (securityDir != null) {
-			pb.command().add(CREDENTIAL_MANAGER_DIRECTORY);
-			pb.command().add(securityDir.getAbsolutePath());
-			out.println("security dir location: " + securityDir);
-		}
-		if (password != null) {
-			pb.command().add(CREDENTIAL_MANAGER_PASSWORD);
-			out.println("password of length " + password.length
-					+ " will be written to subprocess stdin");
-		}
-
-		// Add arguments denoting inputs
-		if (inputBaclava != null) {
-			pb.command().add("-inputdoc");
-			pb.command().add(inputBaclava.getAbsolutePath());
-			if (!inputBaclava.exists())
-				throw new IOException("input baclava file doesn't exist");
-		} else {
-			for (Entry<String, File> port : inputFiles.entrySet()) {
-				if (port.getValue() == null)
-					continue;
-				pb.command().add("-inputfile");
-				pb.command().add(port.getKey());
-				pb.command().add(port.getValue().getAbsolutePath());
-				if (!port.getValue().exists())
-					throw new IOException("input file for port \"" + port
-							+ "\" doesn't exist");
-			}
-			for (Entry<String, String> port : inputValues.entrySet()) {
-				if (port.getValue() == null)
-					continue;
-				pb.command().add("-inputfile");
-				pb.command().add(port.getKey());
-				File f = createTempFile(".tav_in_", null, workingDir);
-				pb.command().add(f.getAbsolutePath());
-				write(f, port.getValue(), "UTF-8");
-			}
-			for (Entry<String, String> delim : inputDelimiters.entrySet()) {
-				if (delim.getValue() == null)
-					continue;
-				pb.command().add("-inputdelimiter");
-				pb.command().add(delim.getKey());
-				pb.command().add(delim.getValue());
-			}
-		}
-
-		// Add arguments denoting outputs
-		if (outputBaclava != null) {
-			pb.command().add("-outputdoc");
-			pb.command().add(outputBaclava.getAbsolutePath());
-			if (!outputBaclava.getParentFile().exists())
-				throw new IOException(
-						"parent directory of output baclava file does not exist");
-			if (outputBaclava.exists())
-				throw new IOException("output baclava file exists");
-			// Provenance cannot be supported when using baclava output
-		} else {
-			File out = new File(workingDir, "out");
-			if (!out.mkdir())
-				throw new IOException("failed to make output directory \"out\"");
-			// Taverna needs the dir to *not* exist now
-			forceDelete(out);
-			pb.command().add("-outputdir");
-			pb.command().add(out.getAbsolutePath());
-			// Enable provenance generation
-			if (generateProvenance) {
-				pb.command().add("-embedded");
-				pb.command().add("-provenance");
-				pb.command().add("-provbundle");
-				pb.command().add("out.bundle.zip");
-			}
-		}
-
-		// Add an argument holding the workflow
-		File tmp = createTempFile(".wf_", ".scufl2", workingDir);
-		try (OutputStream os = new FileOutputStream(tmp)) {
-			os.write(workflow);
-		}
-		pb.command().add(workflowFile.getAbsolutePath());
-
-		// Indicate what working directory to use
-		pb.directory(workingDir);
-		wd = workingDir;
-
-		Map<String, String> env = pb.environment();
-		for (String name : ENVIRONMENT_TO_REMOVE)
-			env.remove(name);
-
-		// Merge any options we have had imposed on us from outside
-		env.putAll(environment);
-
-		// Patch the environment to deal with TAVUTILS-17
-		assert env.get("PATH") != null;
-		env.put("PATH", new File(System.getProperty("java.home"), "bin")
-				+ pathSeparator + env.get("PATH"));
-		// Patch the environment to deal with TAVSERV-189
-		env.put("TAVERNA_APPHOME", workingDir.getCanonicalPath());
-		// Patch the environment to deal with TAVSERV-224
-		env.put("TAVERNA_RUN_ID", token);
-		if (interactionHost != null || local.interactionFeedURL != null
-				|| local.webdavURL != null) {
-			env.put("INTERACTION_HOST", makeInterHost(local.interactionFeedURL));
-			env.put("INTERACTION_PORT", makeInterPort(local.interactionFeedURL));
-			env.put("INTERACTION_FEED", makeInterPath(local.interactionFeedURL));
-			env.put("INTERACTION_WEBDAV",
-					local.webdavURL != null ? local.webdavURL.getPath()
-							: interactionWebdavPath);
-			String pub = makeInterPublish(local.publishURL);
-			if (pub != null && !pub.isEmpty())
-				env.put("INTERACTION_PUBLISH", pub);
-		}
-		return pb;
-	}
-
-	@Nullable
-	private static String makeInterHost(@Nullable URL url) {
-		if (url == null)
-			return interactionHost;
-		return url.getProtocol() + "://" + url.getHost();
-	}
-
-	@Nullable
-	private static String makeInterPort(@Nullable URL url) {
-		if (url == null)
-			return interactionPort;
-		int port = url.getPort();
-		if (port == -1)
-			port = url.getDefaultPort();
-		return Integer.toString(port);
-	}
-
-	@Nullable
-	private static String makeInterPublish(@Nullable URL url)
-			throws IOException {
-		if (url == null)
-			return null;
-		try {
-			URI uri = url.toURI();
-			int port = uri.getPort();
-			if (port == -1)
-				return uri.getScheme() + "://" + uri.getHost();
-			else
-				return uri.getScheme() + "://" + uri.getHost() + ":" + port;
-		} catch (URISyntaxException e) {
-			throw new IOException("problem constructing publication url", e);
-		}
-	}
-
-	@Nullable
-	private static String makeInterPath(@Nullable URL url) {
-		if (url == null)
-			return interactionFeedPath;
-		return url.getPath();
-	}
-
-	/**
-	 * Kills off the subprocess if it exists and is alive.
-	 */
-	@Override
-	public void killWorker() {
-		if (!finished && subprocess != null) {
-			final Holder<Integer> code = new Holder<>();
-			for (TimingOutTask tot : new TimingOutTask[] { new TimingOutTask() {
-				/** Check if the workflow terminated of its own accord */
-				@Override
-				public void doIt() throws IOException {
-					code.value = subprocess.exitValue();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Failed, code.value);
-				}
-			}, new TimingOutTask() {
-				/** Tell the workflow to stop */
-				@Override
-				public void doIt() throws IOException {
-					code.value = killNicely();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Aborted, code.value);
-				}
-			}, new TimingOutTask() {
-				/** Kill the workflow, kill it with fire */
-				@Override
-				public void doIt() throws IOException {
-					code.value = killHard();
-					accounting.runCeased();
-					buildUR(code.value == 0 ? Completed : Aborted, code.value);
-				}
-			} }) {
-				try {
-					tot.doOrTimeOut(DEATH_TIME);
-				} catch (Exception e) {
-				}
-				if (code.value != null)
-					break;
-			}
-			finished = true;
-			setExitCode(code.value);
-			readyToSendEmail = true;
-		}
-	}
-
-	/**
-	 * Integrated spot to handle writing/logging of the exit code.
-	 * 
-	 * @param code
-	 *            The exit code.
-	 */
-	private void setExitCode(int code) {
-		exitCode = code;
-		if (code > 256 - 8) {
-			out.println("workflow aborted, Raven issue = " + (code - 256));
-		} else if (code > 128) {
-			out.println("workflow aborted, signal=" + (code - 128));
-		} else {
-			out.println("workflow exited, code=" + code);
-		}
-	}
-
-	@Nonnull
-	private JobUsageRecord newUR() throws DatatypeConfigurationException {
-		try {
-			if (wd != null)
-				return new JobUsageRecord(wd.getName());
-		} catch (RuntimeException e) {
-		}
-		return new JobUsageRecord("unknown");
-	}
-
-	/**
-	 * Fills in the accounting information from the exit code and stderr.
-	 * 
-	 * @param exitCode
-	 *            The exit code from the program.
-	 */
-	private void buildUR(@Nonnull Status status, int exitCode) {
-		try {
-			Date now = new Date();
-			long user = -1, sys = -1, real = -1;
-			Matcher m = TimeRE.matcher(stderr.toString());
-			ur = newUR();
-			while (m.find())
-				for (int i = 1; i < 6; i += 2)
-					if (m.group(i + 1).equals("user"))
-						user = parseDuration(m.group(i));
-					else if (m.group(i + 1).equals("sys")
-							|| m.group(i + 1).equals("system"))
-						sys = parseDuration(m.group(i));
-					else if (m.group(i + 1).equals("real")
-							|| m.group(i + 1).equals("elapsed"))
-						real = parseDuration(m.group(i));
-			if (user != -1)
-				ur.addCpuDuration(user).setUsageType("user");
-			if (sys != -1)
-				ur.addCpuDuration(sys).setUsageType("system");
-			ur.addUser(System.getProperty("user.name"), null);
-			ur.addStartAndEnd(start, now);
-			if (real != -1)
-				ur.addWallDuration(real);
-			else
-				ur.addWallDuration(now.getTime() - start.getTime());
-			ur.setStatus(status.toString());
-			ur.addHost(getLocalHost().getHostName());
-			ur.addResource("exitcode", Integer.toString(exitCode));
-			ur.addDisk(sizeOfDirectory(wd)).setStorageUnit("B");
-			if (urreceiver != null)
-				urreceiver.acceptUsageRecord(ur.marshal());
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-
-	private long parseDuration(@Nonnull String durationString) {
-		try {
-			return (long) (parseDouble(durationString) * 1000);
-		} catch (NumberFormatException nfe) {
-			// Not a double; maybe MM:SS.mm or HH:MM:SS.mm
-		}
-		long dur = 0;
-		for (String d : durationString.split(":"))
-			try {
-				dur = 60 * dur + parseLong(d);
-			} catch (NumberFormatException nfe) {
-				// Assume that only one thing is fractional, and that it is last
-				return 60000 * dur + (long) (parseDouble(d) * 1000);
-			}
-		return dur * 1000;
-	}
-
-	private void signal(@Nonnull String signal) throws Exception {
-		int pid = getPID();
-		if (pid > 0
-				&& getRuntime().exec("kill -" + signal + " " + pid).waitFor() == 0)
-			return;
-		throw new Exception("failed to send signal " + signal + " to process "
-				+ pid);
-	}
-
-	@Nullable
-	private Integer killNicely() {
-		try {
-			signal("TERM");
-			return subprocess.waitFor();
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	@Nullable
-	private Integer killHard() {
-		try {
-			signal("QUIT");
-			return subprocess.waitFor();
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Move the worker out of the stopped state and back to operating.
-	 * 
-	 * @throws Exception
-	 *             if it fails.
-	 */
-	@Override
-	public void startWorker() throws Exception {
-		signal("CONT");
-		stopped = false;
-	}
-
-	/**
-	 * Move the worker into the stopped state from the operating state.
-	 * 
-	 * @throws Exception
-	 *             if it fails.
-	 */
-	@Override
-	public void stopWorker() throws Exception {
-		signal("STOP");
-		stopped = true;
-	}
-
-	/**
-	 * @return The status of the workflow run. Note that this can be an
-	 *         expensive operation.
-	 */
-	@Override
-	public RemoteStatus getWorkerStatus() {
-		if (subprocess == null)
-			return Initialized;
-		if (finished)
-			return Finished;
-		try {
-			setExitCode(subprocess.exitValue());
-		} catch (IllegalThreadStateException e) {
-			if (stopped)
-				return Stopped;
-			return Operating;
-		}
-		finished = true;
-		readyToSendEmail = true;
-		accounting.runCeased();
-		buildUR(exitCode.intValue() == 0 ? Completed : Failed, exitCode);
-		return Finished;
-	}
-
-	@Override
-	public String getConfiguration() {
-		return "";
-	}
-
-	@Override
-	public String getName() {
-		return DEFAULT_LISTENER_NAME;
-	}
-
-	@Override
-	public String getProperty(String propName) throws RemoteException {
-		switch (Property.is(propName)) {
-		case STDOUT:
-			return stdout.toString();
-		case STDERR:
-			return stderr.toString();
-		case EXIT_CODE:
-			return (exitCode == null) ? "" : exitCode.toString();
-		case EMAIL:
-			return emailAddress;
-		case READY_TO_NOTIFY:
-			return Boolean.toString(readyToSendEmail);
-		case USAGE:
-			try {
-				JobUsageRecord toReturn;
-				if (subprocess == null) {
-					toReturn = newUR();
-					toReturn.setStatus(Held.toString());
-				} else if (ur == null) {
-					toReturn = newUR();
-					toReturn.setStatus(Started.toString());
-					toReturn.addStartAndEnd(start, new Date());
-					toReturn.addUser(System.getProperty("user.name"), null);
-				} else {
-					toReturn = ur;
-				}
-				/*
-				 * Note that this record is not to be pushed to the server. That
-				 * is done elsewhere (when a proper record is produced)
-				 */
-				return toReturn.marshal();
-			} catch (Exception e) {
-				e.printStackTrace();
-				return "";
-			}
-		default:
-			throw new RemoteException("unknown property");
-		}
-	}
-
-	@Override
-	public String getType() {
-		return DEFAULT_LISTENER_NAME;
-	}
-
-	@Override
-	public String[] listProperties() {
-		return Property.names();
-	}
-
-	@Override
-	public void setProperty(String propName, String value)
-			throws RemoteException {
-		switch (Property.is(propName)) {
-		case EMAIL:
-			emailAddress = value;
-			return;
-		case READY_TO_NOTIFY:
-			readyToSendEmail = parseBoolean(value);
-			return;
-		case STDOUT:
-		case STDERR:
-		case EXIT_CODE:
-		case USAGE:
-			throw new RemoteException("property is read only");
-		default:
-			throw new RemoteException("unknown property");
-		}
-	}
-
-	@Override
-	public RemoteListener getDefaultListener() {
-		return this;
-	}
-
-	@Override
-	public void setURReceiver(@Nonnull UsageRecordReceiver receiver) {
-		urreceiver = receiver;
-	}
-
-	@Override
-	public void deleteLocalResources() throws ImplementationException {
-		try {
-			if (workflowFile != null && workflowFile.getParentFile().exists())
-				forceDelete(workflowFile);
-		} catch (IOException e) {
-			throw new ImplementationException("problem deleting workflow file",
-					e);
-		}
-	}
-}
-
-/**
- * An engine for asynchronously copying from an {@link InputStream} to a
- * {@link Writer}.
- * 
- * @author Donal Fellows
- */
-class AsyncCopy extends Thread {
-	@Nonnull
-	private BufferedReader from;
-	@Nonnull
-	private Writer to;
-	@Nullable
-	private Holder<Integer> pidHolder;
-
-	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to)
-			throws UnsupportedEncodingException {
-		this(from, to, null);
-	}
-
-	AsyncCopy(@Nonnull InputStream from, @Nonnull Writer to,
-			@Nullable Holder<Integer> pid) throws UnsupportedEncodingException {
-		this.from = new BufferedReader(new InputStreamReader(from,
-				SYSTEM_ENCODING));
-		this.to = to;
-		this.pidHolder = pid;
-		setDaemon(true);
-		start();
-	}
-
-	@Override
-	public void run() {
-		try {
-			if (pidHolder != null) {
-				String line = from.readLine();
-				if (line.matches("^pid:\\d+$"))
-					synchronized (pidHolder) {
-						pidHolder.value = parseInt(line.substring(4));
-					}
-				else
-					to.write(line + System.getProperty("line.separator"));
-			}
-			copy(from, to);
-		} catch (IOException e) {
-		}
-	}
-}
-
-/**
- * A helper for asynchronously writing a password to a subprocess's stdin.
- * 
- * @author Donal Fellows
- */
-class PasswordWriterThread extends Thread {
-	private OutputStream to;
-	private char[] chars;
-
-	PasswordWriterThread(@Nonnull Process to, @Nonnull char[] chars) {
-		this.to = to.getOutputStream();
-		assert chars != null;
-		this.chars = chars;
-		setDaemon(true);
-		start();
-	}
-
-	@Override
-	public void run() {
-		try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(to,
-				SYSTEM_ENCODING))) {
-			pw.println(chars);
-		} catch (UnsupportedEncodingException e) {
-			// Not much we can do here
-			e.printStackTrace();
-		} finally {
-			/*
-			 * We don't trust GC to clear password from memory. We also take
-			 * care not to clear the default password!
-			 */
-			if (chars != KEYSTORE_PASSWORD)
-				Arrays.fill(chars, '\00');
-		}
-	}
-}
-
-enum Property {
-	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
-			"readyToNotify"), EMAIL("notificationAddress"), USAGE("usageRecord");
-
-	private String s;
-
-	private Property(String s) {
-		this.s = s;
-		pmap.put(s, this);
-	}
-
-	@Override
-	public String toString() {
-		return s;
-	}
-
-	public static Property is(@Nonnull String s) {
-		return pmap.get(s);
-	}
-
-	@Nonnull
-	public static String[] names() {
-		return pmap.keySet().toArray(new String[pmap.size()]);
-	}
-}
-
-enum Status {
-	Aborted, Completed, Failed, Held, Queued, Started, Suspended
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
deleted file mode 100644
index fbc3a72..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/FilenameVerifier.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl.utils;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Utility class that handles filename validation on different target platforms.
- * 
- * @author Donal Fellows.
- */
-public abstract class FilenameVerifier {
-	private FilenameVerifier(){}
-
-	static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
-
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_NAMES = new HashSet<String>(){{
-		add("");
-		add("..");
-		add(".");
-		if (IS_WINDOWS) {
-			add("con");
-			add("prn");
-			add("nul");
-			add("aux");
-			for (int i = 1; i <= 9; i++) {
-				add("com" + i);
-				add("lpt" + i);
-			}
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<Character> ILLEGAL_CHARS = new HashSet<Character>(){{
-		add('/');
-		for (char i=0 ; i<32 ; i++)
-			add(i);
-		if (IS_WINDOWS) {
-			add('\\');
-			add('>');
-			add('<');
-			add(':');
-			add('"');
-			add('|');
-			add('?');
-			add('*');
-		} else {
-			add(' '); // whitespace; too much trouble from these
-			add('\t');
-			add('\r');
-			add('\n');
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_PREFIXES = new HashSet<String>(){{
-		if (IS_WINDOWS) {
-			add("con.");
-			add("prn.");
-			add("nul.");
-			add("aux.");
-			for (int i = 1; i <= 9; i++) {
-				add("com" + i + ".");
-				add("lpt" + i + ".");
-			}
-		}
-	}};
-	@SuppressWarnings("serial")
-	private static final Set<String> ILLEGAL_SUFFIXES = new HashSet<String>(){{
-		if (IS_WINDOWS) {
-			add(" ");
-			add(".");
-		}
-	}};
-
-	/**
-	 * Construct a file handle, applying platform-specific filename validation
-	 * rules in the process.
-	 * 
-	 * @param dir
-	 *            The directory acting as a root, which is assumed to be
-	 *            correctly named. May be <tt>null</tt>.
-	 * @param names
-	 *            The names of filename fragments to apply the checks to. Must
-	 *            have at least one value.
-	 * @return The file handle. Never <tt>null</tt>.
-	 * @throws IOException
-	 *             If validation fails.
-	 */
-	public static File getValidatedFile(File dir, String... names)
-			throws IOException {
-		if (names.length == 0)
-			throw new IOException("empty filename");
-		File f = dir;
-		for (String name : names) {
-			String low = name.toLowerCase();
-			if (ILLEGAL_NAMES.contains(low))
-				throw new IOException("illegal filename");
-			for (char c : ILLEGAL_CHARS)
-				if (low.indexOf(c) >= 0)
-					throw new IOException("illegal filename");
-			for (String s : ILLEGAL_PREFIXES)
-				if (low.startsWith(s))
-					throw new IOException("illegal filename");
-			for (String s : ILLEGAL_SUFFIXES)
-				if (low.endsWith(s))
-					throw new IOException("illegal filename");
-			f = new File(f, name);
-		}
-		assert f != null;
-		return f;
-	}
-
-	/**
-	 * Create a file handle where the underlying file must exist.
-	 * 
-	 * @param dir
-	 *            The directory that will contain the file.
-	 * @param name
-	 *            The name of the file; will be validated.
-	 * @return The handle.
-	 * @throws IOException
-	 *             If validation fails or the file doesn't exist.
-	 */
-	public static File getValidatedExistingFile(File dir, String name)
-			throws IOException {
-		File f = getValidatedFile(dir, name);
-		if (!f.exists())
-			throw new IOException("doesn't exist");
-		return f;
-	}
-
-	/**
-	 * Create a file handle where the underlying file must <i>not</i> exist.
-	 * 
-	 * @param dir
-	 *            The directory that will contain the file.
-	 * @param name
-	 *            The name of the file; will be validated.
-	 * @return The handle. The file will not be created by this method.
-	 * @throws IOException
-	 *             If validation fails or the file does exist.
-	 */
-	public static File getValidatedNewFile(File dir, String name)
-			throws IOException {
-		File f = getValidatedFile(dir, name);
-		if (f.exists())
-			throw new IOException("already exists");
-		return f;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
----------------------------------------------------------------------
diff --git a/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java b/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
deleted file mode 100644
index 3dd3ac1..0000000
--- a/server-worker/src/main/java/org/taverna/server/localworker/impl/utils/TimingOutTask.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.taverna.server.localworker.impl.utils;
-
-import javax.annotation.Nullable;
-
-/**
- * A class that handles running a task that can take some time.
- * 
- * @author Donal Fellows
- * 
- */
-public abstract class TimingOutTask extends Thread {
-	public abstract void doIt() throws Exception;
-
-	@Nullable
-	private Exception ioe;
-
-	@Override
-	public final void run() {
-		try {
-			doIt();
-		} catch (Exception ioe) {
-			this.ioe = ioe;
-		}
-	}
-
-	public TimingOutTask() {
-		this.setDaemon(true);
-	}
-
-	public void doOrTimeOut(long timeout) throws Exception {
-		start();
-		try {
-			join(timeout);
-		} catch (InterruptedException e) {
-			interrupt();
-		}
-		if (ioe != null)
-			throw ioe;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/main/resources/security.policy
----------------------------------------------------------------------
diff --git a/server-worker/src/main/resources/security.policy b/server-worker/src/main/resources/security.policy
deleted file mode 100644
index 5b5c322..0000000
--- a/server-worker/src/main/resources/security.policy
+++ /dev/null
@@ -1,11 +0,0 @@
-//keystore "signers.jks";
-//grant signedBy "taverna" {
-//   permission java.util.PropertyPermission "*", "read,write";
-//   permission java.lang.RuntimePermission "shutdownHooks";
-//   permission java.lang.RuntimePermission "exitVM";
-//   permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute,delete";
-//   permission java.net.SocketPermission "localhost:1024-" "accept,connect,listen";
-//};
-grant {
-   permission java.security.AllPermission "*:*";
-};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
----------------------------------------------------------------------
diff --git a/server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java b/server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
deleted file mode 100644
index 7bcd92e..0000000
--- a/server-worker/src/test/java/org/taverna/server/localworker/impl/LocalWorkerTest.java
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.localworker.impl;
-
-import static java.util.UUID.randomUUID;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.taverna.server.localworker.impl.LocalWorker.DO_MKDIR;
-
-import java.io.File;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.taverna.server.localworker.api.Worker;
-import org.taverna.server.localworker.api.WorkerFactory;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.server.UsageRecordReceiver;
-
-public class LocalWorkerTest {
-	LocalWorker lw;
-	static List<String> events;
-
-	public static RemoteStatus returnThisStatus = RemoteStatus.Operating;
-
-	static class DummyWorker implements Worker {
-		@Override
-		public RemoteListener getDefaultListener() {
-			return new RemoteListener() {
-				@Override
-				public String getConfiguration() {
-					return "RLCONFIG";
-				}
-
-				@Override
-				public String getName() {
-					return "RLNAME";
-				}
-
-				@Override
-				public String getProperty(String propName) {
-					return "RLPROP[" + propName + "]";
-				}
-
-				@Override
-				public String getType() {
-					return "RLTYPE";
-				}
-
-				@Override
-				public String[] listProperties() {
-					return new String[] { "RLP1", "RLP2" };
-				}
-
-				@Override
-				public void setProperty(String propName, String value) {
-					events.add("setProperty[");
-					events.add(propName);
-					events.add(value);
-					events.add("]");
-				}
-			};
-		}
-
-		@Override
-		public RemoteStatus getWorkerStatus() {
-			events.add("status=" + returnThisStatus);
-			return returnThisStatus;
-		}
-
-		@Override
-		public boolean initWorker(LocalWorker local,
-				String executeWorkflowCommand, byte[] workflow,
-				File workingDir, File inputBaclava,
-				Map<String, File> inputFiles, Map<String, String> inputValues,
-				Map<String, String> delimiters, File outputBaclava, File cmdir,
-				char[] cmpass, boolean doprov, Map<String, String> env,
-				String id, List<String> conf) throws Exception {
-			events.add("init[");
-			events.add(executeWorkflowCommand);
-			events.add(new String(workflow, "UTF-8"));
-			int dirLen = workingDir.getName().length();
-			events.add(Integer.toString(dirLen));
-			events.add(inputBaclava == null ? "<null>" : inputBaclava
-					.toString().substring(dirLen));
-			Map<String, String> in = new TreeMap<>();
-			for (Entry<String, File> name : inputFiles.entrySet())
-				in.put(name.getKey(), name.getValue() == null ? "<null>" : name
-						.getValue().getName());
-			events.add(in.toString());
-			events.add(new TreeMap<>(inputValues).toString());
-			events.add(outputBaclava == null ? "<null>" : outputBaclava
-					.getName());
-			// TODO: check cmdir and cmpass
-			// TODO: check doprov
-			// TODO: log env
-			// TODO: check delimiters
-			events.add("]");
-			return true;
-		}
-
-		@Override
-		public void killWorker() throws Exception {
-			events.add("kill");
-		}
-
-		@Override
-		public void startWorker() throws Exception {
-			events.add("start");
-		}
-
-		@Override
-		public void stopWorker() throws Exception {
-			events.add("stop");
-		}
-
-		@Override
-		public void setURReceiver(UsageRecordReceiver receiver) {
-			// We just ignore this
-		}
-
-		@Override
-		public void deleteLocalResources() throws ImplementationException {
-			// Nothing to do here
-		}
-	}
-
-	WorkerFactory factory = new WorkerFactory() {
-		@Override
-		public Worker makeInstance() throws Exception {
-			return new DummyWorker();
-		}
-	};
-
-	@Before
-	public void setUp() throws Exception {
-		lw = new LocalWorker("XWC", "WF".getBytes("UTF-8"), null, randomUUID(),
-				new HashMap<String, String>(), new ArrayList<String>(), factory);
-		events = new ArrayList<>();
-		returnThisStatus = RemoteStatus.Operating;
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		lw.destroy();
-	}
-
-	private List<String> l(String... strings) {
-		return Arrays.asList(strings);
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	@Test
-	public void testDestroy1() throws Exception {
-		lw.destroy();
-		assertEquals(l(), events);
-	}
-
-	@Test
-	public void testDestroy2() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-	}
-
-	@Test
-	public void testDestroy3() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "kill"), events);
-	}
-
-	@Test
-	public void testDestroy4() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-		lw.destroy();
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "kill"), events);
-	}
-
-	@Test
-	public void testAddListener() {
-		Throwable t = null;
-		try {
-			lw.addListener(null);
-		} catch (Throwable caught) {
-			t = caught;
-		}
-		assertNotNull(t);
-		assertSame(ImplementationException.class, t.getClass());
-		assertNotNull(t.getMessage());
-		assertEquals("not implemented", t.getMessage());
-	}
-
-	@Test
-	public void testGetInputBaclavaFile() throws Exception {
-		assertNull(lw.getInputBaclavaFile());
-		lw.setInputBaclavaFile("IBaclava");
-		assertNotNull(lw.getInputBaclavaFile());
-		assertEquals("IBaclava", lw.getInputBaclavaFile());
-		lw.makeInput("FOO").setValue("BAR");
-		assertNull(lw.getInputBaclavaFile());
-	}
-
-	@Test
-	public void testGetInputsWithValue() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		lw.makeInput("FOO").setValue("BAR");
-
-		assertEquals(1, lw.getInputs().size());
-		assertEquals("FOO", lw.getInputs().get(0).getName());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNotNull(lw.getInputs().get(0).getValue());
-
-		lw.setInputBaclavaFile("BLAH");
-
-		assertEquals(1, lw.getInputs().size());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-	}
-
-	@Test
-	public void testGetInputsWithFile() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		lw.makeInput("BAR").setFile("FOO");
-
-		assertEquals(1, lw.getInputs().size());
-		assertEquals("BAR", lw.getInputs().get(0).getName());
-		assertNotNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-
-		lw.setInputBaclavaFile("BLAH");
-
-		assertEquals(1, lw.getInputs().size());
-		assertNull(lw.getInputs().get(0).getFile());
-		assertNull(lw.getInputs().get(0).getValue());
-	}
-
-	@Test
-	public void testGetListenerTypes() {
-		assertEquals("[]", lw.getListenerTypes().toString());
-	}
-
-	@Test
-	public void testGetListeners() throws Exception {
-		assertEquals(1, lw.getListeners().size());
-		RemoteListener rl = lw.getListeners().get(0);
-		assertEquals("RLNAME", rl.getName());
-		assertEquals("RLCONFIG", rl.getConfiguration());
-		assertEquals("RLTYPE", rl.getType());
-		assertEquals("[RLP1, RLP2]", Arrays.asList(rl.listProperties())
-				.toString());
-		assertEquals("RLPROP[RLP1]", rl.getProperty("RLP1"));
-		assertEquals("RLPROP[RLP2]", rl.getProperty("RLP2"));
-		rl.setProperty("FOOBAR", "BARFOO");
-		assertEquals(l("setProperty[", "FOOBAR", "BARFOO", "]"), events);
-	}
-
-	@Test
-	public void testGetOutputBaclavaFile() throws Exception {
-		assertNull(lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile("notnull");
-		assertEquals("notnull", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile(null);
-		assertNull(lw.getOutputBaclavaFile());
-	}
-
-	@Test
-	public void testGetSecurityContext() throws Exception {
-		boolean md = DO_MKDIR;
-		LocalWorker.DO_MKDIR = false; // HACK! Work around Hudson problem...
-		try {
-			assertNotNull(lw.getSecurityContext());
-		} finally {
-			LocalWorker.DO_MKDIR = md;
-		}
-	}
-
-	@Test
-	public void testGetStatusInitial() {
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-	}
-
-	@Test
-	public void testGetStatus() throws Exception {
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-		returnThisStatus = RemoteStatus.Operating;
-		assertEquals(RemoteStatus.Initialized, lw.getStatus());
-		lw.setStatus(RemoteStatus.Operating);
-		assertEquals(RemoteStatus.Operating, lw.getStatus());
-		assertEquals(RemoteStatus.Operating, lw.getStatus());
-		returnThisStatus = RemoteStatus.Finished;
-		assertEquals(RemoteStatus.Finished, lw.getStatus());
-		returnThisStatus = RemoteStatus.Stopped;
-		assertEquals(RemoteStatus.Finished, lw.getStatus());
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "status=Operating", "status=Operating",
-						"status=Finished"), events);
-	}
-
-	@Test
-	public void testGetWorkingDirectory() throws Exception {
-		RemoteDirectory rd = lw.getWorkingDirectory();
-		assertNotNull(rd);
-		assertNotNull(rd.getContents());
-		assertNull(rd.getContainingDirectory());
-		assertNotNull(rd.getName());
-		assertEquals(-1, rd.getName().indexOf('/'));
-		assertFalse("..".equals(rd.getName()));
-		assertEquals("", rd.getName());
-	}
-
-	@Test
-	public void testValidateFilename() throws Exception {
-		lw.validateFilename("foobar");
-		lw.validateFilename("foo/bar");
-		lw.validateFilename("foo.bar");
-		lw.validateFilename("foo..bar");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad0() throws Exception {
-		lw.validateFilename("./.");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad1() throws Exception {
-		lw.validateFilename("/");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad2() throws Exception {
-		lw.validateFilename("");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad3() throws Exception {
-		lw.validateFilename(null);
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad4() throws Exception {
-		lw.validateFilename("..");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testValidateFilenameBad5() throws Exception {
-		lw.validateFilename("foo/../bar");
-	}
-
-	@Test
-	public void testMakeInput() throws Exception {
-		assertEquals(0, lw.getInputs().size());
-
-		RemoteInput ri = lw.makeInput("TEST");
-
-		assertNotNull(ri);
-		assertEquals(1, lw.getInputs().size());
-		assertNotSame(ri, lw.getInputs().get(0)); // different delegates
-		assertEquals("TEST", ri.getName());
-		assertNull(ri.getFile());
-		assertNull(ri.getValue());
-
-		lw.setInputBaclavaFile("bad");
-		ri.setFile("good");
-		assertEquals("good", ri.getFile());
-		assertNull(lw.getInputBaclavaFile());
-		ri.setValue("very good");
-		assertEquals("very good", ri.getValue());
-		assertNull(ri.getFile());
-		assertNull(lw.getInputBaclavaFile());
-
-		lw.makeInput("TEST2");
-		assertEquals(2, lw.getInputs().size());
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testMakeInputFileSanity() throws Exception {
-		lw.makeInput("foo").setFile("/../bar");
-	}
-
-	@Test
-	public void testMakeListener() {
-		Throwable t = null;
-		try {
-			lw.makeListener("?", "?");
-		} catch (Throwable caught) {
-			t = caught;
-		}
-		assertNotNull(t);
-		assertSame(RemoteException.class, t.getClass());
-		assertNotNull(t.getMessage());
-		assertEquals("listener manufacturing unsupported", t.getMessage());
-	}
-
-	@Test
-	public void testSetInputBaclavaFile1() throws Exception {
-		assertNull(lw.getInputBaclavaFile());
-		lw.setInputBaclavaFile("eg");
-		assertEquals("eg", lw.getInputBaclavaFile());
-	}
-
-	@Test
-	public void testSetInputBaclavaFile2() throws Exception {
-		RemoteInput ri = lw.makeInput("foo");
-		ri.setValue("bar");
-		assertEquals("bar", ri.getValue());
-		lw.setInputBaclavaFile("eg");
-		assertNull(ri.getValue());
-	}
-
-	@Test
-	public void testSetOutputBaclavaFile1() throws Exception {
-		assertNull(lw.outputBaclava);
-		lw.setOutputBaclavaFile("foobar");
-		assertEquals("foobar", lw.outputBaclava);
-		assertEquals("foobar", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile("foo/bar");
-		assertEquals("foo/bar", lw.outputBaclava);
-		assertEquals("foo/bar", lw.getOutputBaclavaFile());
-		lw.setOutputBaclavaFile(null);
-		assertNull(lw.outputBaclava);
-		assertNull(lw.getOutputBaclavaFile());
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testSetOutputBaclavaFile2() throws Exception {
-		lw.setOutputBaclavaFile("/foobar");
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void testSetOutputBaclavaFile3() throws Exception {
-		lw.setOutputBaclavaFile("foo/../bar");
-	}
-
-	@Test
-	public void testSetStatus0() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "start", "kill"), events);
-	}
-
-	@Test
-	public void testSetStatus1() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>", "{}", "{}", "<null>",
-						"]", "stop", "kill"), events);
-	}
-
-	@Test
-	public void testSetStatus2() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Finished);
-		assertEquals(l(), events);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus3() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus4() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus5() throws Exception {
-		lw.setStatus(RemoteStatus.Initialized);
-		lw.setStatus(RemoteStatus.Stopped);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus6() throws Exception {
-		lw.setStatus(RemoteStatus.Finished);
-		lw.setStatus(RemoteStatus.Stopped);
-	}
-
-	@Test(expected = IllegalStateTransitionException.class)
-	public void testSetStatus7() throws Exception {
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Stopped);
-		lw.setStatus(RemoteStatus.Initialized);
-	}
-
-	@Test
-	public void testLifecycle() throws Exception {
-		lw.makeInput("foo").setFile("foofile");
-		lw.makeInput("bar").setValue("barvalue");
-		lw.setOutputBaclavaFile("spong");
-		lw.setOutputBaclavaFile("boo");
-		lw.setStatus(RemoteStatus.Operating);
-		lw.setStatus(RemoteStatus.Finished);
-		// Assumes order of map, so fragile but works...
-		assertEquals(
-				l("init[", "XWC", "WF", "36", "<null>",
-						"{bar=<null>, foo=foofile}",
-						"{bar=barvalue, foo=null}", "boo", "]", "kill"), events);
-	}
-}


[36/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
deleted file mode 100644
index f387cf6..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static java.lang.Math.min;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.rest.FileSegment;
-
-/**
- * How to write out a segment of a file with JAX-RS.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class FileSegmentHandler implements MessageBodyWriter<FileSegment> {
-	/** How much to pull from the worker in one read. */
-	private int maxChunkSize;
-
-	/**
-	 * @param maxChunkSize
-	 *            How much to pull from the worker in one read.
-	 */
-	public void setMaxChunkSize(int maxChunkSize) {
-		this.maxChunkSize = maxChunkSize;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return FileSegment.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public long getSize(FileSegment t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return t.to - t.from;
-	}
-
-	@Override
-	public void writeTo(FileSegment t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			int off = t.from;
-			while (off < t.to) {
-				byte[] buffer = t.file.getContents(off,
-						min(maxChunkSize, t.to - off));
-				if (buffer == null || buffer.length == 0)
-					break;
-				entityStream.write(buffer);
-				off += buffer.length;
-			}
-		} catch (FilesystemAccessException e) {
-			throw new IOException("problem when reading file", e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
deleted file mode 100644
index 12c137e..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-
-@Provider
-public class FilesystemAccessHandler extends HandlerCore implements
-		ExceptionMapper<FilesystemAccessException> {
-	@Override
-	public Response toResponse(FilesystemAccessException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
deleted file mode 100644
index 775805b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.GeneralFailureException;
-
-public class GeneralFailureHandler extends HandlerCore implements
-		ExceptionMapper<GeneralFailureException> {
-	@Override
-	public Response toResponse(GeneralFailureException exception) {
-		return respond(INTERNAL_SERVER_ERROR, exception);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
deleted file mode 100644
index 0e3fb51..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
-import static javax.ws.rs.core.Response.status;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import javax.ws.rs.core.Response;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.master.api.ManagementModel;
-
-/**
- * Base class for handlers that grants Spring-enabled access to the management
- * model.
- * 
- * @author Donal Fellows
- */
-public class HandlerCore {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private ManagementModel managementModel;
-
-	/**
-	 * @param managementModel
-	 *            the managementModel to set
-	 */
-	public void setManagementModel(ManagementModel managementModel) {
-		this.managementModel = managementModel;
-	}
-
-	/**
-	 * Simplified interface for building responses.
-	 * 
-	 * @param status
-	 *            What status code to use?
-	 * @param exception
-	 *            What exception to report on?
-	 * @return The build response.
-	 */
-	protected Response respond(Response.Status status, Exception exception) {
-		if (managementModel.getLogOutgoingExceptions()
-				|| status.getStatusCode() >= 500)
-			log.info("converting exception to response", exception);
-		return status(status).type(TEXT_PLAIN_TYPE)
-				.entity(exception.getMessage()).build();
-	}
-
-	/**
-	 * Simplified interface for building responses.
-	 * 
-	 * @param status
-	 *            What status code to use?
-	 * @param partialMessage
-	 *            The prefix to the message.
-	 * @param exception
-	 *            What exception to report on?
-	 * @return The build response.
-	 */
-	protected Response respond(Response.Status status, String partialMessage,
-			Exception exception) {
-		if (managementModel.getLogOutgoingExceptions()
-				|| status.getStatusCode() >= 500)
-			log.info("converting exception to response", exception);
-		return status(status).type(TEXT_PLAIN_TYPE)
-				.entity(partialMessage + "\n" + exception.getMessage()).build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
deleted file mode 100644
index ac02015..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.UNSUPPORTED_MEDIA_TYPE;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class IllegalArgumentHandler extends HandlerCore implements
-		ExceptionMapper<IllegalArgumentException> {
-	@Override
-	public Response toResponse(IllegalArgumentException exn) {
-		return respond(UNSUPPORTED_MEDIA_TYPE, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
deleted file mode 100644
index 1458667..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.localworker.remote.ImplementationException;
-
-public class ImplementationProblemHandler extends HandlerCore implements
-		ExceptionMapper<ImplementationException> {
-	@Override
-	public Response toResponse(ImplementationException exception) {
-		return respond(INTERNAL_SERVER_ERROR, exception);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
deleted file mode 100644
index 2c0c092..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static java.lang.Long.parseLong;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
-import static org.apache.commons.logging.LogFactory.getLog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.Provider;
-
-import org.apache.commons.logging.Log;
-
-/**
- * Maps a stream from a client into a bounded ordinary input stream that the
- * webapp can work with more easily.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Consumes(APPLICATION_OCTET_STREAM)
-public class InputStreamMessageHandler implements
-		MessageBodyReader<InputStream> {
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return InputStream.class.isAssignableFrom(type);
-	}
-
-	@Override
-	public InputStream readFrom(Class<InputStream> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		return new TransferStream(entityStream,
-				httpHeaders.get("Content-Length"));
-	}
-}
-
-/**
- * The actual transfer thunk.
- * 
- * @author Donal Fellows
- */
-class TransferStream extends InputStream {
-	private Log log = getLog("Taverna.Server.Handlers");
-
-	public TransferStream(InputStream entityStream, List<String> contentLength) {
-		this.entityStream = new BufferedInputStream(entityStream);
-		if (contentLength != null && contentLength.size() > 0) {
-			this.limit = parseLong(contentLength.get(0));
-			if (log.isDebugEnabled())
-				log.debug("will attempt to transfer " + this.limit + " bytes");
-		} else {
-			this.limit = -1;
-			if (log.isDebugEnabled())
-				log.debug("will attempt to transfer until EOF");
-		}
-	}
-
-	InputStream entityStream;
-	long limit;
-	long doneBytes = 0;
-
-	@Override
-	public int read() throws IOException {
-		if (limit >= 0 && doneBytes >= limit)
-			return -1;
-		int result = entityStream.read();
-		if (result >= 0)
-			doneBytes++;
-		return result;
-	}
-
-	@Override
-	public int read(byte[] ary, int off, int len) throws IOException {
-		if (limit >= 0) {
-			if (doneBytes >= limit)
-				return -1;
-			if (doneBytes + len > limit)
-				len = (int) (limit - doneBytes);
-		}
-		int readBytes = entityStream.read(ary, off, len);
-		if (readBytes >= 0)
-			doneBytes += readBytes;
-		return readBytes;
-	}
-
-	@Override
-	public void close() throws IOException {
-		entityStream.close();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
deleted file mode 100644
index fe11de8..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-
-@Provider
-public class InvalidCredentialHandler extends HandlerCore implements
-		ExceptionMapper<InvalidCredentialException> {
-	@Override
-	public Response toResponse(InvalidCredentialException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
deleted file mode 100644
index 33ac6a0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-import javax.xml.bind.JAXBException;
-
-@Provider
-public class JAXBExceptionHandler extends HandlerCore implements
-		ExceptionMapper<JAXBException> {
-	@Override
-	public Response toResponse(JAXBException exn) {
-		return respond(BAD_REQUEST, "APIEpicFail: " + exn.getErrorCode(), exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
deleted file mode 100644
index 47153e7..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
-import static javax.ws.rs.core.Response.notAcceptable;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
-
-@Provider
-public class NegotiationFailedHandler implements
-		ExceptionMapper<NegotiationFailedException> {
-	@Override
-	public Response toResponse(NegotiationFailedException exn) {
-		return notAcceptable(exn.accepted).type(TEXT_PLAIN)
-				.entity(exn.getMessage()).build();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
deleted file mode 100644
index e4215a1..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoCreateException;
-
-@Provider
-public class NoCreateHandler extends HandlerCore implements
-		ExceptionMapper<NoCreateException> {
-	@Override
-	public Response toResponse(NoCreateException exn) {
-		return respond(SERVICE_UNAVAILABLE, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
deleted file mode 100644
index d81f6ba..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.NoCredentialException;
-
-public class NoCredentialHandler extends HandlerCore implements
-		ExceptionMapper<NoCredentialException> {
-	@Override
-	public Response toResponse(NoCredentialException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
deleted file mode 100644
index 927af4b..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoDestroyException;
-
-@Provider
-public class NoDestroyHandler extends HandlerCore implements
-		ExceptionMapper<NoDestroyException> {
-	@Override
-	public Response toResponse(NoDestroyException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
deleted file mode 100644
index ab2e54d..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-
-@Provider
-public class NoDirectoryEntryHandler extends HandlerCore implements
-		ExceptionMapper<NoDirectoryEntryException> {
-	@Override
-	public Response toResponse(NoDirectoryEntryException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
deleted file mode 100644
index 36e3053..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoListenerException;
-
-@Provider
-public class NoListenerHandler extends HandlerCore implements
-		ExceptionMapper<NoListenerException> {
-	@Override
-	public Response toResponse(NoListenerException exn) {
-		return respond(BAD_REQUEST, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
deleted file mode 100644
index 61a89d4..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.NoUpdateException;
-
-@Provider
-public class NoUpdateHandler extends HandlerCore implements
-		ExceptionMapper<NoUpdateException> {
-	@Override
-	public Response toResponse(NoUpdateException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
deleted file mode 100644
index 44de871..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.FORBIDDEN;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-
-import org.taverna.server.master.exceptions.NotOwnerException;
-
-public class NotOwnerHandler extends HandlerCore implements
-		ExceptionMapper<NotOwnerException> {
-	@Override
-	public Response toResponse(NotOwnerException exn) {
-		return respond(FORBIDDEN, exn);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
deleted file mode 100644
index 21e5e68..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.OverloadedException;
-
-@Provider
-public class OverloadedHandler extends HandlerCore implements
-		ExceptionMapper<OverloadedException> {
-	@Override
-	public Response toResponse(OverloadedException exn) {
-		return respond(SERVICE_UNAVAILABLE, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
deleted file mode 100644
index 03a4dd4..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-
-import org.taverna.server.master.common.Permission;
-
-/**
- * Handler that allows CXF to send and receive {@linkplain Permission
- * permissions} as plain text directly.
- * 
- * @author Donal Fellows
- */
-public class PermissionHandler implements MessageBodyReader<Permission>,
-		MessageBodyWriter<Permission> {
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(Permission.class)
-				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
-	}
-
-	@Override
-	public long getSize(Permission t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return t.toString().length();
-	}
-
-	@Override
-	public void writeTo(Permission t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		new OutputStreamWriter(entityStream).write(t.toString());
-	}
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(Permission.class)
-				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
-	}
-
-	@Override
-	public Permission readFrom(Class<Permission> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		char[] cbuf = new char[7];
-		int len = new InputStreamReader(entityStream).read(cbuf);
-		if (len < 0)
-			throw new IllegalArgumentException("no entity supplied");
-		return Permission.valueOf(new String(cbuf, 0, len));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
deleted file mode 100644
index edeac63..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE.txt" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.common.Workflow;
-
-import uk.org.taverna.scufl2.api.io.ReaderException;
-import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
-import uk.org.taverna.scufl2.api.io.WriterException;
-
-/**
- * Handler that allows a .scufl2 document to be read from and written to a REST
- * message directly.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class Scufl2DocumentHandler implements MessageBodyReader<Workflow>,
-		MessageBodyWriter<Workflow> {
-	private static final MediaType SCUFL2_TYPE = new MediaType("application",
-			"vnd.taverna.scufl2.workflow-bundle");
-	public static final String SCUFL2 = "application/vnd.taverna.scufl2.workflow-bundle";
-	private WorkflowBundleIO io = new WorkflowBundleIO();
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (type.isAssignableFrom(Workflow.class))
-			return mediaType.isCompatible(SCUFL2_TYPE);
-		return false;
-	}
-
-	@Override
-	public Workflow readFrom(Class<Workflow> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		try {
-			return new Workflow(io.readBundle(entityStream, SCUFL2));
-		} catch (ReaderException e) {
-			throw new WebApplicationException(e, 403);
-		}
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (Workflow.class.isAssignableFrom(type))
-			return mediaType.isCompatible(SCUFL2_TYPE);
-		return false;
-	}
-
-	@Override
-	public long getSize(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			io.writeBundle(workflow.getScufl2Workflow(), entityStream, SCUFL2);
-		} catch (WriterException e) {
-			throw new WebApplicationException(e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
deleted file mode 100644
index 4227d80..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.taverna.server.master.common.Workflow;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-/**
- * Handler that allows a .t2flow document to be read from and written to a REST
- * message directly.
- * 
- * @author Donal Fellows
- */
-@Provider
-public class T2FlowDocumentHandler implements MessageBodyReader<Workflow>,
-		MessageBodyWriter<Workflow> {
-	private static final MediaType T2FLOW_TYPE = new MediaType("application",
-			"vnd.taverna.t2flow+xml");
-	public static final String T2FLOW = "application/vnd.taverna.t2flow+xml";
-	public static final String T2FLOW_ROOTNAME = "workflow";
-	public static final String T2FLOW_NS = "http://taverna.sf.net/2008/xml/t2flow";
-	private DocumentBuilderFactory db;
-	private TransformerFactory transformer;
-
-	public T2FlowDocumentHandler() throws ParserConfigurationException,
-			TransformerConfigurationException {
-		db = DocumentBuilderFactory.newInstance();
-		db.setNamespaceAware(true);
-		transformer = TransformerFactory.newInstance();
-	}
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (type.isAssignableFrom(Workflow.class))
-			return mediaType.isCompatible(T2FLOW_TYPE);
-		return false;
-	}
-
-	@Override
-	public Workflow readFrom(Class<Workflow> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		Document doc;
-		try {
-			doc = db.newDocumentBuilder().parse(entityStream);
-		} catch (SAXException e) {
-			throw new WebApplicationException(e, 403);
-		} catch (ParserConfigurationException e) {
-			throw new WebApplicationException(e);
-		}
-		Workflow workflow = new Workflow(doc.getDocumentElement());
-		if (doc.getDocumentElement().getNamespaceURI().equals(T2FLOW_NS)
-				&& doc.getDocumentElement().getNodeName()
-						.equals(T2FLOW_ROOTNAME))
-			return workflow;
-		throw new WebApplicationException(Response.status(403)
-				.entity("invalid T2flow document; bad root element")
-				.type("text/plain").build());
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		if (Workflow.class.isAssignableFrom(type))
-			return mediaType.isCompatible(T2FLOW_TYPE);
-		return false;
-	}
-
-	@Override
-	public long getSize(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		try {
-			transformer.newTransformer().transform(
-					new DOMSource(workflow.getT2flowWorkflow()),
-					new StreamResult(entityStream));
-		} catch (TransformerException e) {
-			if (e.getCause() != null && e.getCause() instanceof IOException)
-				throw (IOException) e.getCause();
-			throw new WebApplicationException(e);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
deleted file mode 100644
index a90a229..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.status;
-import static org.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Deserialization and serialization engine for the <tt>{@value #URI_LIST}</tt>
- * content type.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Consumes(URI_LIST)
-public class URIListHandler implements MessageBodyReader<List<URI>>,
-		MessageBodyWriter<List<URI>> {
-	/** The content type we handle. */
-	public static final String URI_LIST = "text/uri-list";
-	private static final MediaType URILIST = new MediaType("text", "uri-list");
-
-	@Override
-	public boolean isReadable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return type.isAssignableFrom(ArrayList.class)
-				&& genericType instanceof ParameterizedType
-				&& ((Class<?>) ((ParameterizedType) genericType)
-						.getActualTypeArguments()[0])
-						.isAssignableFrom(URI.class)
-				&& URILIST.isCompatible(mediaType);
-	}
-
-	@Override
-	public List<URI> readFrom(Class<List<URI>> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-			throws IOException, WebApplicationException {
-		String enc = mediaType.getParameters().get("encoding");
-		Charset c = (enc == null) ? Charset.defaultCharset() : Charset
-				.forName(enc);
-		BufferedReader br = new BufferedReader(new InputStreamReader(
-				entityStream, c));
-		ArrayList<URI> uris = new ArrayList<>();
-		String line;
-		while ((line = br.readLine()) != null) {
-			if (line.startsWith("#"))
-				continue;
-			try {
-				uris.add(new URI(line));
-			} catch (URISyntaxException e) {
-				throw new WebApplicationException(e, status(422).entity(
-						"ill-formed URI").build());
-			}
-		}
-		return uris;
-	}
-
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return List.class.isAssignableFrom(type)
-				&& genericType instanceof ParameterizedType
-				&& ((ParameterizedType) genericType).getActualTypeArguments()[0] == URI.class
-				&& URILIST.isCompatible(mediaType);
-	}
-
-	@Override
-	public long getSize(List<URI> list, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	private static final String PREFERRED_ENCODING = "UTF-8";
-
-	@Override
-	public void writeTo(List<URI> list, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException {
-		String encoding = mediaType.getParameters().get("encoding");
-		if (encoding == null) {
-			encoding = PREFERRED_ENCODING;
-			httpHeaders.putSingle("Content-Type", URI_LIST + ";encoding="
-					+ encoding);
-		}
-		BufferedWriter w = new BufferedWriter(new OutputStreamWriter(
-				entityStream, encoding));
-		for (URI uri : list) {
-			w.write(uri.toString());
-			w.newLine();
-		}
-		w.flush();
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
deleted file mode 100644
index 4542237..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.exceptions.UnknownRunException;
-
-@Provider
-public class UnknownRunHandler extends HandlerCore implements
-		ExceptionMapper<UnknownRunException> {
-	@Override
-	public Response toResponse(UnknownRunException exn) {
-		return respond(NOT_FOUND, exn);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
deleted file mode 100644
index 2241220..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.rest.handler;
-
-import static org.apache.commons.io.IOUtils.copy;
-import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import org.taverna.server.master.interfaces.Directory.ZipStream;
-
-/**
- * How to write a ZIP file as the result entity of a request.
- * 
- * @author Donal Fellows
- */
-@Provider
-@Produces("application/zip")
-public class ZipStreamHandler implements MessageBodyWriter<ZipStream> {
-	@Override
-	public boolean isWriteable(Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return ZipStream.class.isAssignableFrom(type)
-				&& mediaType.equals(APPLICATION_ZIP_TYPE);
-	}
-
-	@Override
-	public long getSize(ZipStream t, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType) {
-		return -1;
-	}
-
-	@Override
-	public void writeTo(ZipStream zipStream, Class<?> type, Type genericType,
-			Annotation[] annotations, MediaType mediaType,
-			MultivaluedMap<String, Object> httpHeaders,
-			OutputStream entityStream) throws IOException,
-			WebApplicationException {
-		copy(zipStream, entityStream);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
deleted file mode 100644
index e72af22..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains type handlers for the RESTful interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest.handler;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
deleted file mode 100644
index 0a0b069..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * This package contains the RESTful interface to Taverna Server.
- * @author Donal Fellows
- */
-@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
-		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
-		@XmlNs(prefix = "ts", namespaceURI = SERVER),
-		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
-		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
-		@XmlNs(prefix = "port", namespaceURI = DATA),
-		@XmlNs(prefix = "feed", namespaceURI = FEED),
-		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
-package org.taverna.server.master.rest;
-
-import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
-import static org.taverna.server.master.common.Namespaces.ADMIN;
-import static org.taverna.server.master.common.Namespaces.FEED;
-import static org.taverna.server.master.common.Namespaces.SERVER;
-import static org.taverna.server.master.common.Namespaces.SERVER_REST;
-import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
-import static org.taverna.server.master.common.Namespaces.XLINK;
-import static org.taverna.server.port_description.Namespaces.DATA;
-
-import javax.xml.bind.annotation.XmlNs;
-import javax.xml.bind.annotation.XmlSchema;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java b/server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
deleted file mode 100644
index bb8d73f..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import static org.taverna.server.master.common.Namespaces.XLINK;
-
-import java.net.URI;
-
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlSchemaType;
-import javax.xml.bind.annotation.XmlSeeAlso;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.DirEntryReference;
-
-/**
- * A more Taverna-friendly version of the directory entry descriptor classes.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "DirectoryEntry")
-@XmlRootElement(name = "entry")
-@XmlSeeAlso({ DirEntry.File.class, DirEntry.Directory.class })
-public class DirEntry {
-	/** A link to the entry. Ignored on input. */
-	@XmlAttribute(name = "href", namespace = XLINK)
-	@XmlSchemaType(name = "anyURI")
-	public URI link;
-	@XmlAttribute
-	public String name;
-	@XmlElement(required = true)
-	public String path;
-
-	/**
-	 * A file in a directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "FileDirEntry")
-	@XmlRootElement(name = "file")
-	public static class File extends DirEntry {
-	}
-
-	/**
-	 * A directory in a directory. That is, a sub-directory.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "DirectoryDirEntry")
-	@XmlRootElement(name = "dir")
-	public static class Directory extends DirEntry {
-	}
-
-	/**
-	 * Converts from the "common" format to the subclasses of this class.
-	 * 
-	 * @param deref
-	 *            The "common" format handle to convert.
-	 * @return The converted handle
-	 */
-	public static DirEntry convert(DirEntryReference deref) {
-		DirEntry result;
-		if (deref instanceof DirEntryReference.DirectoryReference)
-			result = new Directory();
-		else if (deref instanceof DirEntryReference.FileReference)
-			result = new File();
-		else
-			result = new DirEntry();
-		result.link = deref.link;
-		result.name = deref.name;
-		result.path = deref.path;
-		return result;
-	}
-
-	/**
-	 * Converts to the "common" format from the subclasses of this class.
-	 * 
-	 * @param deref
-	 *            The subclass of this class to convert.
-	 * @return The converted reference.
-	 */
-	public static DirEntryReference convert(DirEntry de) {
-		DirEntryReference result;
-		if (de instanceof Directory)
-			result = new DirEntryReference.DirectoryReference();
-		else if (de instanceof File)
-			result = new DirEntryReference.FileReference();
-		else
-			result = new DirEntryReference();
-		result.link = de.link;
-		result.name = de.name;
-		result.path = de.path;
-		return result;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java b/server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
deleted file mode 100644
index 7ebc991..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import static java.lang.Math.min;
-import static java.lang.System.arraycopy;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.activation.DataHandler;
-import javax.activation.DataSource;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlMimeType;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.interfaces.File;
-
-/**
- * An MTOM-capable description of how to transfer the contents of a file.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "FileContents")
-public class FileContents {
-	@XmlElement
-	public String name;
-	@XmlMimeType("application/octet-stream") // JAXB bug: must be this
-	public DataHandler fileData;
-
-	/**
-	 * Initialize the contents of this descriptor from the given file and
-	 * content type.
-	 * 
-	 * @param file
-	 *            The file that is to be reported.
-	 * @param contentType
-	 *            The estimated content type of the file.
-	 */
-	public void setFile(File file, String contentType) {
-		name = file.getFullName();
-		fileData = new DataHandler(new TavernaFileSource(file, contentType));
-	}
-
-	/**
-	 * Write the content described by this class to the specified file.
-	 * @param file The file to write to; must already exist.
-	 * @throws IOException
-	 * @throws FilesystemAccessException
-	 */
-	public void writeToFile(File file) throws IOException,
-			FilesystemAccessException {
-		try (InputStream is = fileData.getInputStream()) {
-			byte[] buf = new byte[65536];
-			file.setContents(new byte[0]);
-			while (true) {
-				int len = is.read(buf);
-				if (len <= 0)
-					return;
-				if (len == buf.length)
-					file.appendContents(buf);
-				else {
-					byte[] shortbuf = new byte[len];
-					arraycopy(buf, 0, shortbuf, 0, len);
-					file.appendContents(shortbuf);
-				}
-			}
-		}
-	}
-}
-
-/**
- * A data source that knows how to communicate with the Taverna Server back-end.
- * 
- * @author Donal Fellows
- */
-class TavernaFileSource implements DataSource {
-	TavernaFileSource(File f, String type) {
-		this.f = f;
-		this.type = type;
-	}
-
-	private final File f;
-	private final String type;
-
-	@Override
-	public String getContentType() {
-		return type;
-	}
-
-	@Override
-	public String getName() {
-		return f.getName();
-	}
-
-	@Override
-	public InputStream getInputStream() throws IOException {
-		final File f = this.f;
-		return new InputStream() {
-			private int idx;
-
-			@Override
-			public int read(byte[] b, int off, int len) throws IOException {
-				byte[] r;
-				try {
-					r = f.getContents(idx, len);
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-				if (r == null)
-					return -1;
-				len = min(len, r.length);
-				arraycopy(r, 0, b, off, len);
-				idx += len;
-				return len;
-			}
-
-			@Override
-			public int read() throws IOException {
-				byte[] r;
-				try {
-					r = f.getContents(idx, 1);
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-				if (r == null)
-					return -1;
-				idx++;
-				return r[0];
-			}
-		};
-	}
-
-	@Override
-	public OutputStream getOutputStream() throws IOException {
-		final File f = this.f;
-		return new OutputStream() {
-			private boolean append = false;
-
-			@Override
-			public void write(int b) throws IOException {
-				write(new byte[] { (byte) b });
-			}
-
-			@Override
-			public void write(byte[] b) throws IOException {
-				try {
-					if (append)
-						f.appendContents(b);
-					else
-						f.setContents(b);
-					append = true;
-				} catch (FilesystemAccessException e) {
-					throw new IOException(e);
-				}
-			}
-
-			@Override
-			public void write(byte[] b, int off, int len) throws IOException {
-				byte[] ary = new byte[len];
-				arraycopy(b, off, ary, 0, len);
-				write(ary);
-			}
-		};
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java b/server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
deleted file mode 100644
index 3ab6d0c..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.soap;
-
-import java.util.List;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-import org.taverna.server.master.common.Permission;
-
-/**
- * The list of permissions to access a workflow run of users <i>other than the
- * owner</i>. This class exists to support the JAXB mapping.
- * 
- * @author Donal Fellows
- */
-@XmlType(name = "PermissionList")
-@XmlRootElement(name = "permissionList")
-public class PermissionList {
-	/**
-	 * The type of a single mapped permission. This class exists to support the
-	 * JAXB mapping.
-	 * 
-	 * @author Donal Fellows
-	 */
-	@XmlType(name = "")
-	public static class SinglePermissionMapping {
-		public SinglePermissionMapping() {
-		}
-
-		public SinglePermissionMapping(String user, Permission permission) {
-			this.userName = user;
-			this.permission = permission;
-		}
-
-		/** The name of the user that this talks about. */
-		public String userName;
-		/** The permission level that the user is granted. */
-		public Permission permission;
-	}
-
-	/** The list of (non-default) permissions granted. */
-	@XmlElement
-	public List<SinglePermissionMapping> permission;
-}
\ No newline at end of file


[31/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/admin.js
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/admin.js b/server-webapp/src/main/resources/static/admin.js
deleted file mode 100644
index c2c41bf..0000000
--- a/server-webapp/src/main/resources/static/admin.js
+++ /dev/null
@@ -1,549 +0,0 @@
-// Wrappers round AJAX calls to simplify *most* of this stuff
-
-/** How to retrieve text asynchronously. */
-function getText(u, done) {
-	$.ajax({
-		type : "GET",
-		url : u,
-		async : true,
-		cache : false,
-		accept : "text/plain",
-		dataType : "text",
-		success : done
-	});
-}
-/** How to retrieve JSON asynchronously. */
-function getJSON(u, done) {
-	$.ajax({
-		type : "GET",
-		url : u,
-		async : true,
-		cache : false,
-		dataType : "json",
-		accept : "application/json",
-		success : done
-	});
-}
-/** How to send a PUT of text asynchronously. */
-function putText(u, val, done) {
-	$.ajax({
-		type : "PUT",
-		url : u,
-		async : false,
-		cache : false,
-		data : val,
-		contentType : "text/plain",
-		dataType : "text",
-		processData : false,
-		success : done,
-		error : function(jqXHR, textStatus, errorThrown) {
-			alert(errorThrown);
-		}
-	});
-}
-/** How to send a PUT of XML asynchronously. */
-function putXML(u, xml, done) {
-	$.ajax({
-		type : "PUT",
-		url : u,
-		async : false,
-		cache : false,
-		contentType : "application/xml",
-		data : new XMLSerializer().serializeToString(xml),
-		success : done,
-		error : function(jqXHR, textStatus, errorThrown) {
-			alert(errorThrown);
-		}
-	});
-}
-/** How to send a POST of XML asynchronously. */
-function postXML(u, xml, done) {
-	$.ajax({
-		type : "POST",
-		url : u,
-		async : false,
-		cache : false,
-		contentType : "application/xml",
-		data : new XMLSerializer().serializeToString(xml),
-		success : done,
-		error : function(jqXHR, textStatus, errorThrown) {
-			alert(errorThrown);
-		}
-	});
-}
-/** How to send a DELETE asynchronously. */
-function deleteUrl(u, done) {
-	$.ajax({
-		type : "DELETE",
-		url : u,
-		async : true,
-		cache : false,
-		success : done,
-		error : function(jqXHR, textStatus, errorThrown) {
-			alert(errorThrown);
-		}
-	});
-}
-
-/** Locates a URL with respect to the administrative REST interface. */
-function where(tail) {
-	return $("#admin")[0].href + "/" + tail;
-}
-
-// Make an XML element structure
-// Derived from hack on Stack Overflow, but with extra tinkering
-/** Function called to create a node in an XML structure. */
-var Node;
-/** Function called to create nodes in an XML structure from an array. */
-var NodeAll;
-(function() {
-	var doc = document.implementation.createDocument(null, null, null);
-	var adminNS = "http://ns.taverna.org.uk/2010/xml/server/admin/";
-	Node = function() {
-		var node = doc.createElementNS(adminNS, arguments[0]), child;
-		for ( var i = 1; i < arguments.length; i++) {
-			child = arguments[i];
-			if (child == undefined)
-				continue;
-			if (typeof child != 'object')
-				child = doc.createTextNode(child.toString());
-			node.appendChild(child);
-		}
-		return node;
-	};
-	NodeAll = function(wrapperElem, wrappedElem, elements) {
-		var node = doc.createElementNS(adminNS, wrapperElem);
-		for ( var i = 0; i < elements.length; i++) {
-			var child = doc.createElementNS(adminNS, wrappedElem);
-			var text = doc.createTextNode(elements[i]);
-			child.appendChild(text);
-			node.appendChild(child);
-		}
-		return node;
-	};
-})();
-
-/** The IDs of boolean-coupled buttons. */
-var buttonlist = [ "allowNew", "logFaults", "logWorkflows", "generateProvenance" ];
-/** The IDs of values that track server variables without setting things. */
-var readonlies = [ "invokationCount", "lastExitCode", "runCount", "startupTime", "operatingCount" ];
-/** The IDs of text/numeric-coupled entries. */
-var entries = [ "defaultLifetime", "executeWorkflowScript", "javaBinary",
-		"registrationPollMillis", "registrationWaitSeconds", "registryHost",
-		"registryPort", "runLimit", "runasPasswordFile", "serverForkerJar",
-		"serverWorkerJar", "usageRecordDumpFile", "operatingLimit",
-		"registryJar" ];
-/** Cached information about users. */
-var userinfo = [];
-/** Extra arguments to pass to the runtime. */
-var extraAry = [];
-
-/** How to update the read-only fields; will be called periodically */
-function updateRO() {
-	$.each(readonlies, function(idx, val) {
-		var widget = $("#" + val);
-		getText(where(val), function(data) {
-			widget.html(data);
-		});
-	});
-	getJSON(where("factoryProcessMapping"),
-			function(data) {
-				var ary = data.stringList.string;
-				var tbl = $("#factoryProcessMapping");
-				tbl.html("<tr><th>User<th>ID</tr>");
-				if (ary != undefined)
-					for ( var i = 0; i < ary.length - 1; i += 2)
-						tbl.append("<tr><td>" + ary[i] + "<td>" + ary[i + 1]
-								+ "</tr>");
-			});
-}
-
-/**
- * Generate a user row with suitable indices, but no content (it will be pushed
- * into the row later).
- */
-function userRowHTML(idx) {
-	// USER NAME
-	var content = "<td><span id='username" + idx
-			+ "' title='The login name of the user.'></span></td>";
-	// SYSTEM ID MAPPING
-	content += "<td><input id='userlocal"
-			+ idx
-			+ "' title='The system username to run workflows as, or blank for default.' /></td>";
-	// ENABLED
-	content += "<td><label title='Is this user allowed to log in?' for='useron"
-			+ idx + "'>Enabled</label>" + "<input type='checkbox' id='useron"
-			+ idx + "' /></td>";
-	// ADMIN
-	content += "<td><label title='Is this user an admin (allowed to access this page)?' for='useradmin"
-			+ idx
-			+ "'>Admin</label>"
-			+ "<input type='checkbox' id='useradmin"
-			+ idx + "' /></td>";
-	// SET PASSWORD
-	content += "<td><button title='Set the password for this user.' id='userpass"
-			+ idx + "'>Set Password</button></td>";
-	// DELETE
-	content += "<td><button title='Delete this user. Take care to not delete yourself!' id='userdel"
-			+ idx + "'>Delete</button></td>";
-
-	return "<tr id='usersep" + idx + "' class='userrows'>"
-			+ "<td colspan=6><hr></td></tr>" + "<tr id='userrow" + idx
-			+ "' class='userrows'>" + content + "</tr>";
-}
-
-/** How to get the list of permitted workflows; called on demand */
-function refreshWorkflows() {
-	var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows"), wfref = $("#refreshWorkflows");
-	wfbut.button("disable");
-	wfbut1.button("disable");
-	wfref.button("disable");
-	getJSON(where("permittedWorkflowURIs"), function(data) {
-		var s = "";
-		$.each(data.stringList.string || [], function(idx, str) {
-			s += $.trim(str) + "\n";
-		});
-		wftable.val($.trim(s));
-		wfbut.button("enable");
-		wfbut1.button("enable");
-		wfref.button("enable");
-	});
-}
-/** How to set the list of permitted workflows; called when the user clicks */
-function saveWorkflows() {
-	var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
-	var xml = NodeAll("stringList", "string", wftable.val().split("\n"));
-	wfbut.button("disable");
-	wfbut1.button("disable");
-	putXML(where("permittedWorkflowURIs"), xml, function() {
-		refreshWorkflows();
-	});
-}
-
-/** How to empty the list of permitted workflows; called when the user clicks */
-function emptyWorkflows() {
-        var wftable = $("#workflows"), wfbut = $("#saveWorkflows"), wfbut1 = $("#emptyWorkflows");
-        var xml = NodeAll("stringList", "string", "");
-        wfbut.button("disable");
-        wfbut1.button("disable");
-        putXML(where("permittedWorkflowURIs"), xml, function() {
-                refreshWorkflows();
-        });
-}
-
-/** How to update the table of users; called on demand */
-function refreshUsers() {
-	var usertable = $("#userList");
-	getJSON(where("users"), function(data) {
-		$(".userrows").remove();
-		userinfo = [];
-		$.each(data.userList.user, function(idx, url) {
-			usertable.append(userRowHTML(idx));
-			var i = idx;
-			userinfo[i] = {
-				url : url
-			};
-			getJSON(url, function(data) {
-				var model = userinfo[i].model = data.userDesc;
-				$("#username" + i).html(model.username);
-				$("#userlocal" + i).val(model.localUserId).change(function() {
-					updateUser(i, "localUserId", $(this).val());
-				});
-				$("#useron" + i).button().attr("checked", model.enabled)
-						.button("refresh").click(
-								function() {
-									updateUser(i, "enabled", $(this).attr(
-											"checked") == "checked");
-								});
-				$("#useradmin" + i).button().attr("checked", model.admin)
-						.button("refresh").click(
-								function() {
-									updateUser(i, "admin", $(this).attr(
-											"checked") == "checked");
-								});
-				$("#userpass" + i).button({
-					icons : {
-						primary : "ui-icon-alert"
-					}
-				}).click(function() {
-					updatePasswordUser(i);
-				});
-				$("#userdel" + i).button({
-					icons : {
-						primary : "ui-icon-trash"
-					},
-					text : false
-				}).click(function() {
-					deleteUser(i);
-				});
-			});
-			return true;
-		});
-	});
-}
-
-/** How to delete a user by index (with dialog) */
-function deleteUser(idx) {
-	$("#dialog-confirm").dialog({
-		modal : true,
-		autoOpen : false,
-		buttons : {
-			"OK" : function() {
-				$(this).dialog("close");
-				deleteUrl(userinfo[idx].url, function() {
-					refreshUsers();
-				});
-			},
-			"Cancel" : function() {
-				$(this).dialog("close");
-			}
-		}
-	});
-	$("#dialog-confirm").dialog("open");
-}
-
-/** How to update a user's password by index (with dialog) */
-function updatePasswordUser(idx) {
-	$("#change-password").val("");
-	$("#change-password2").val("");
-	$("#dialog-password").dialog({
-		modal : true,
-		autoOpen : false,
-		buttons : {
-			"OK" : function() {
-				$(this).dialog("close");
-				var pass = $("#change-password").val();
-				var pass2 = $("#change-password2").val();
-				$("#change-password").val("");
-				$("#change-password2").val("");
-				if (pass.equals(pass2))
-					updateUser(idx, "password", pass);
-			},
-			"Cancel" : function() {
-				$(this).dialog("close");
-				$("#change-password").val("");
-			}
-		}
-	});
-	$("#dialog-password").dialog("open");
-}
-
-/** How to set a specific field of a user record */
-function updateUser(idx, field, value) {
-	var model = userinfo[idx].model;
-	var xml = Node("userDesc", Node("username", model.username),
-			field == "password" ? Node("password", value) : undefined,
-			field == "localUserId" ? Node("localUserId", value)
-					: model.localUserId == undefined ? undefined : Node(
-							"localUserId", model.localUserId), Node("enabled",
-					field == "enabled" ? value : model.enabled), Node("admin",
-					field == "admin" ? value : model.admin));
-	putXML(userinfo[idx].url, xml, function() {
-		refreshUsers();
-	});
-}
-
-/** How to configure all the buttons and entries */
-function connectButtonsAndEntries() {
-	$.each(buttonlist, function(idx, val) {
-		var widget = $("#" + val);
-		var u = where(val);
-		widget.button();
-		getText(u, function(data) {
-			widget.attr('checked', (data + "") != "false");
-			widget.button("refresh");
-		});
-		widget.change(function() {
-			putText(u, widget.attr("checked") == "checked", function(data) {
-				widget.attr('checked', (data + "") != "false");
-				widget.button("refresh");
-				return true;
-			});
-		});
-	});
-	$.each(entries, function(idx, val) {
-		var widget = $("#" + val);
-		var u = where(val);
-		getText(u, function(data) {
-			widget.val(data);
-		});
-		widget.change(function() {
-			putText(u, widget.val(), function(data) {
-				widget.val(data);
-				return true;
-			});
-		});
-	});
-}
-
-/** What happens when the user tries to make a new user */
-function makeNewUser() {
-	var sysid = $("#newSysID").val();
-	var newuserinfo = {
-		admin : $("#newAdmin").attr("checked") == "checked",
-		enabled : $("#newEnabled").attr("checked") == "checked",
-		username : $("#newUsername").val(),
-		password : $("#newPassword").val()
-	};
-	// Blank out the password immediately!
-	$("#newPassword").val("");
-	if (sysid.length > 0) {
-		newuserinfo.localUserId = sysid;
-	}
-	if (newuserinfo.username == "" || newuserinfo.password == "") {
-		alert("Won't create user; need a username and a password!");
-		return;
-	}
-	var xml = newuserinfo = Node("userDesc", Node("username",
-			newuserinfo.username), Node("password", newuserinfo.password),
-			newuserinfo.localUserId == undefined ? undefined : Node(
-					"localUserId", newuserinfo.localUserId), Node("enabled",
-					newuserinfo.enabled), Node("admin", newuserinfo.admin));
-	postXML(where("users"), xml, function() {
-		refreshUsers();
-	});
-}
-
-/** Handle the extra arguments */
-function loadExtraArgs() {
-	getJSON(where("extraArguments"),
-			function(data) {
-				var rows = data.stringList.string || [];
-				if ((typeof rows) == "string")
-					rows = [ rows ];
-				$(".extraargrow").remove();
-				extraAry = rows;
-				var i;
-				function row() {
-					var buf = "<tr class='extraargrow'>";
-					for ( var i = 1; i < arguments.length; i++)
-						buf += "<td>" + arguments[i] + "</td>";
-					return $(arguments[0]).append(buf + "</tr>");
-				}
-				function delbutn(id, what) {
-					return "<button id='" + id + "' title='Delete this " + what
-							+ ".'>Del</button>";
-				}
-				for (i = 0; i < extraAry.length; i++) {
-					var rowid = "extradel" + i;
-					if (rows[i].match("^-D")) {
-						var m = rows[i].match("^-D([^=]*)=(.*)$");
-						row("#extraArguments-prop", delbutn(rowid,
-								"property assignment"), "<tt><b>-D</b>" + m[1]
-								+ "<b>=</b>" + m[2] + "</tt>");
-					} else if (rows[i].match("-E")) {
-						var m = rows[i].match("^-E([^=]*)=(.*)$");
-						row("#extraArguments-env", delbutn(rowid,
-								"environment assignment"), "<tt><b>-E</b>"
-								+ m[1] + "<b>=</b>" + m[2] + "</tt>");
-					} else {
-						var m = rows[i].match("^-J(.*)$");
-						row("#extraArguments-runtime", delbutn(rowid,
-								"runtime parameter"), "<tt><b>-J</b>" + m[1]
-								+ "</tt>");
-					}
-					$("#" + rowid).button({
-						icons : {
-							primary : "ui-icon-trash"
-						},
-						text : false
-					}).click(
-							(function(row) {
-								return function() {
-									extraAry.splice(row, 1);
-									var xml = NodeAll("stringList", "string",
-											extraAry);
-									putXML(where("extraArguments"), xml,
-											function() {
-												loadExtraArgs();
-											});
-								};
-							})(i));
-				}
-			});
-}
-
-/** Run a dialog for creating an extra argument. */
-function addExtraArg(dialogId, prefix, part1id, part2id) {
-	$(dialogId).dialog({
-		modal : true,
-		autoOpen : false,
-		buttons : {
-			"OK" : function() {
-				$(this).dialog("close");
-				var str = prefix + $(part1id).val();
-				if (part2id != undefined)
-					str += "=" + $(part2id).val();
-				extraAry.push(str);
-				var xml = NodeAll("stringList", "string", extraAry);
-				putXML(where("extraArguments"), xml, function() {
-					loadExtraArgs();
-				});
-			},
-			"Cancel" : function() {
-				$(this).dialog("close");
-			}
-		}
-	});
-	$(dialogId).dialog("open");
-}
-
-/** Start everything going on page load */
-$(function() {
-	// Must be done in this order because the accordion is inside a tab
-	$("#a-worker").accordion({
-		collapsible : true,
-		fillSpace : true,
-		autoHeight : false
-	});
-	$("#body").tabs({
-		selected : 0
-	});
-	$("#saveWorkflows").button({
-		disabled : true
-	}).click(function(event) {
-		saveWorkflows();
-		event.preventDefault();
-	});
-	$("#refreshWorkflows").button({
-		disabled : true
-	}).click(function(event) {
-		refreshWorkflows();
-		event.preventDefault();
-	});
-	$("#emptyWorkflows").button({
-                disabled : true
-        }).click(function(event) {
-                emptyWorkflows();
-                event.preventDefault();
-        });
-
-	// Make the link to the list of usage records point correctly
-	// Original plan called for browsable table, but that's too slow
-	$("#ur").attr("href", where("usageRecords"));
-
-	connectButtonsAndEntries();
-	updateRO();
-	setInterval(updateRO, 30000);
-	refreshUsers();
-	refreshWorkflows();
-	$("#newEnabled").button();
-	$("#newAdmin").button({
-		icons : {
-			primary : "ui-icon-alert"
-		}
-	});
-	$("#makeNewUser").button().click(function() {
-		makeNewUser();
-	});
-	$("#extra-prop-add").button().click(function() {
-		addExtraArg("#dialog-property", "-D", "#prop-key", "#prop-value");
-	});
-	$("#extra-env-add").button().click(function() {
-		addExtraArg("#dialog-environment", "-E", "#env-key", "#env-value");
-	});
-	$("#extra-run-add").button().click(function() {
-		addExtraArg("#dialog-runtime", "-J", "#runtime-value");
-	});
-	loadExtraArgs();
-});


[48/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
taverna-* module names


Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/commit/2c71f9a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/tree/2c71f9a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/diff/2c71f9a9

Branch: refs/heads/master
Commit: 2c71f9a95c7fe6c525cacedeac76646262059dfe
Parents: 529e59d
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Mon Feb 23 15:33:34 2015 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Mon Feb 23 15:33:34 2015 +0000

----------------------------------------------------------------------
 pom.xml                                         |   20 +-
 server-client/pom.xml                           |  130 --
 .../uk/org/taverna/server/client/Connected.java |   20 -
 .../uk/org/taverna/server/client/DirEntry.java  |   39 -
 .../uk/org/taverna/server/client/Directory.java |   94 --
 .../java/uk/org/taverna/server/client/File.java |   95 --
 .../uk/org/taverna/server/client/Property.java  |   18 -
 .../java/uk/org/taverna/server/client/Run.java  |  215 ---
 .../uk/org/taverna/server/client/Status.java    |   36 -
 .../taverna/server/client/TavernaServer.java    |  128 --
 .../client/TavernaServerConnectionFactory.java  |   23 -
 .../org/taverna/server/client/package-info.java |    5 -
 server-client/src/main/wadl/tavserv.wadl        |  591 -------
 server-distribution/pom.xml                     |  145 --
 server-distribution/src/assemble/dist.xml       |   82 -
 server-execution-delegate/pom.xml               |   41 -
 .../execution_delegate/ExecutionDelegate.java   |  172 --
 .../execution_delegate/RemoteExecution.java     |  188 ---
 .../src/test/java/SerializationTest.java        |   54 -
 server-port-description/.gitignore              |    1 -
 server-port-description/pom.xml                 |   45 -
 .../server/port_description/AbsentValue.java    |   13 -
 .../server/port_description/AbstractPort.java   |   26 -
 .../AbstractPortDescription.java                |   29 -
 .../server/port_description/AbstractValue.java  |   32 -
 .../server/port_description/ErrorValue.java     |   25 -
 .../port_description/InputDescription.java      |   51 -
 .../server/port_description/LeafValue.java      |   19 -
 .../server/port_description/ListValue.java      |   32 -
 .../server/port_description/Namespaces.java     |   12 -
 .../port_description/OutputDescription.java     |   52 -
 .../server/port_description/package-info.java   |   19 -
 .../port_description/utils/IntAdapter.java      |   32 -
 .../server/port_description/JaxbSanityTest.java |   98 --
 server-rmidaemon/pom.xml                        |   61 -
 .../org/taverna/server/rmidaemon/Registry.java  |   72 -
 .../taverna/server/rmidaemon/package-info.java  |    5 -
 server-runinterface/.gitignore                  |    1 -
 server-runinterface/pom.xml                     |   30 -
 .../src/main/java/META-INF/MANIFEST.MF          |    3 -
 .../remote/IllegalStateTransitionException.java |   36 -
 .../remote/ImplementationException.java         |   26 -
 .../localworker/remote/RemoteDirectory.java     |   62 -
 .../remote/RemoteDirectoryEntry.java            |   62 -
 .../server/localworker/remote/RemoteFile.java   |   98 --
 .../server/localworker/remote/RemoteInput.java  |   92 --
 .../localworker/remote/RemoteListener.java      |   77 -
 .../localworker/remote/RemoteRunFactory.java    |   84 -
 .../remote/RemoteSecurityContext.java           |   34 -
 .../localworker/remote/RemoteSingleRun.java     |  254 ---
 .../server/localworker/remote/RemoteStatus.java |   40 -
 .../remote/StillWorkingOnItException.java       |   20 -
 .../server/localworker/remote/package-info.java |    9 -
 .../localworker/server/UsageRecordReceiver.java |   29 -
 .../server/localworker/server/package-info.java |    9 -
 server-unix-forker/pom.xml                      |   61 -
 .../org/taverna/server/unixforker/Forker.java   |  208 ---
 server-usagerecord/.gitignore                   |    1 -
 server-usagerecord/pom.xml                      |   79 -
 .../main/java/org/ogf/usage/JobUsageRecord.java |  304 ----
 server-usagerecord/src/main/xsd/ur.xsd          |  425 -----
 server-usagerecord/src/main/xsd/xmlds.xsd       |  318 ----
 server-usagerecord/src/test/java/TestUR.java    |  120 --
 server-webapp/.gitignore                        |    1 -
 server-webapp/.springBeans                      |   59 -
 server-webapp/pom.xml                           |  889 ----------
 .../resources/datanucleus_log4j.properties      |    4 -
 .../master/ContentsDescriptorBuilder.java       |  292 ----
 .../taverna/server/master/DirectoryREST.java    |  375 -----
 .../server/master/FileConcatenation.java        |   68 -
 .../org/taverna/server/master/InputREST.java    |  252 ---
 .../taverna/server/master/InteractionFeed.java  |  107 --
 .../server/master/ListenerPropertyREST.java     |   78 -
 .../taverna/server/master/ListenersREST.java    |   93 --
 .../taverna/server/master/ManagementState.java  |  215 ---
 .../java/org/taverna/server/master/RunREST.java |  499 ------
 .../taverna/server/master/RunSecurityREST.java  |  303 ----
 .../server/master/SingleListenerREST.java       |   97 --
 .../taverna/server/master/TavernaServer.java    | 1425 ----------------
 .../server/master/TavernaServerSupport.java     |  957 -----------
 .../org/taverna/server/master/admin/Admin.java  | 1100 -------------
 .../taverna/server/master/admin/AdminBean.java  |  794 ---------
 .../server/master/admin/package-info.java       |   33 -
 .../taverna/server/master/api/ContentTypes.java |   50 -
 .../server/master/api/DirectoryBean.java        |   16 -
 .../org/taverna/server/master/api/FeedBean.java |   13 -
 .../taverna/server/master/api/InputBean.java    |   21 -
 .../server/master/api/ListenerPropertyBean.java |   15 -
 .../server/master/api/ListenersBean.java        |   13 -
 .../server/master/api/ManagementModel.java      |   61 -
 .../server/master/api/OneListenerBean.java      |   14 -
 .../org/taverna/server/master/api/RunBean.java  |   17 -
 .../taverna/server/master/api/SecurityBean.java |   14 -
 .../taverna/server/master/api/SupportAware.java |   21 -
 .../server/master/api/TavernaServerBean.java    |  101 --
 .../taverna/server/master/api/package-info.java |    6 -
 .../server/master/common/Capability.java        |   22 -
 .../server/master/common/Credential.java        |  149 --
 .../server/master/common/DirEntryReference.java |   93 --
 .../server/master/common/InputDescription.java  |  110 --
 .../server/master/common/Namespaces.java        |   39 -
 .../server/master/common/Permission.java        |   43 -
 .../server/master/common/ProfileList.java       |   42 -
 .../org/taverna/server/master/common/Roles.java |   25 -
 .../server/master/common/RunReference.java      |   67 -
 .../taverna/server/master/common/Status.java    |   44 -
 .../org/taverna/server/master/common/Trust.java |   79 -
 .../org/taverna/server/master/common/Uri.java   |  432 -----
 .../server/master/common/VersionedElement.java  |   65 -
 .../taverna/server/master/common/Workflow.java  |  367 -----
 .../server/master/common/package-info.java      |   29 -
 .../server/master/common/version/Version.java   |   43 -
 .../taverna/server/master/defaults/Default.java |   99 --
 .../server/master/defaults/package-info.java    |    5 -
 .../exceptions/BadInputPortNameException.java   |   21 -
 .../exceptions/BadPropertyValueException.java   |   26 -
 .../exceptions/BadStateChangeException.java     |   35 -
 .../exceptions/FilesystemAccessException.java   |   38 -
 .../exceptions/GeneralFailureException.java     |   28 -
 .../exceptions/InvalidCredentialException.java  |   36 -
 .../master/exceptions/NoCreateException.java    |   32 -
 .../exceptions/NoCredentialException.java       |   18 -
 .../master/exceptions/NoDestroyException.java   |   24 -
 .../exceptions/NoDirectoryEntryException.java   |   24 -
 .../master/exceptions/NoListenerException.java  |   33 -
 .../master/exceptions/NoUpdateException.java    |   33 -
 .../master/exceptions/NotOwnerException.java    |   23 -
 .../master/exceptions/OverloadedException.java  |   35 -
 .../master/exceptions/UnknownRunException.java  |   27 -
 .../server/master/exceptions/package-info.java  |   29 -
 .../taverna/server/master/facade/Facade.java    |   73 -
 .../server/master/facade/package-info.java      |   10 -
 .../factories/ConfigurableRunFactory.java       |  133 --
 .../master/factories/ListenerFactory.java       |   46 -
 .../server/master/factories/RunFactory.java     |   40 -
 .../server/master/factories/package-info.java   |   10 -
 .../identity/AuthorityDerivedIDMapper.java      |   50 -
 .../master/identity/CompositeIDMapper.java      |   65 -
 .../master/identity/ConstantIDMapper.java       |   32 -
 .../server/master/identity/NameIDMapper.java    |   50 -
 .../identity/StrippedDownAuthProvider.java      |  278 ----
 .../taverna/server/master/identity/User.java    |  153 --
 .../server/master/identity/UserStore.java       |  389 -----
 .../server/master/identity/UserStoreAPI.java    |   91 -
 .../identity/WorkflowInternalAuthProvider.java  |  304 ----
 .../server/master/identity/package-info.java    |   10 -
 .../interaction/InteractionFeedSupport.java     |  316 ----
 .../server/master/interaction/package-info.java |   10 -
 .../server/master/interfaces/Directory.java     |   82 -
 .../master/interfaces/DirectoryEntry.java       |   47 -
 .../taverna/server/master/interfaces/File.java  |   69 -
 .../taverna/server/master/interfaces/Input.java |   92 --
 .../server/master/interfaces/Listener.java      |   64 -
 .../master/interfaces/LocalIdentityMapper.java  |   29 -
 .../master/interfaces/MessageDispatcher.java    |   45 -
 .../server/master/interfaces/Policy.java        |  120 --
 .../server/master/interfaces/RunStore.java      |   82 -
 .../interfaces/SecurityContextFactory.java      |   32 -
 .../server/master/interfaces/TavernaRun.java    |  219 ---
 .../interfaces/TavernaSecurityContext.java      |  213 ---
 .../master/interfaces/UriBuilderFactory.java    |   43 -
 .../server/master/interfaces/package-info.java  |   10 -
 .../localworker/AbstractRemoteRunFactory.java   |  440 -----
 .../master/localworker/ForkRunFactory.java      |  323 ----
 .../localworker/IdAwareForkRunFactory.java      |  516 ------
 .../master/localworker/LocalWorkerFactory.java  |   31 -
 .../master/localworker/LocalWorkerState.java    |  454 -----
 .../master/localworker/PersistedState.java      |  257 ---
 .../server/master/localworker/StreamLogger.java |   62 -
 .../server/master/localworker/package-info.java |   10 -
 .../master/notification/EmailDispatcher.java    |  113 --
 .../master/notification/JabberDispatcher.java   |  140 --
 .../master/notification/NotificationEngine.java |  145 --
 .../notification/RateLimitedDispatcher.java     |   89 -
 .../master/notification/SMSDispatcher.java      |  158 --
 .../master/notification/TwitterDispatcher.java  |  132 --
 .../master/notification/atom/AtomFeed.java      |  134 --
 .../server/master/notification/atom/Event.java  |  110 --
 .../master/notification/atom/EventDAO.java      |  206 ---
 .../master/notification/atom/package-info.java  |   29 -
 .../master/notification/package-info.java       |   10 -
 .../org/taverna/server/master/package-info.java |   11 -
 .../server/master/rest/ContentTypes.java        |   28 -
 .../server/master/rest/DirectoryContents.java   |   61 -
 .../taverna/server/master/rest/FileSegment.java |   78 -
 .../server/master/rest/InteractionFeedREST.java |  126 --
 .../server/master/rest/ListenerDefinition.java  |   32 -
 .../master/rest/MakeOrUpdateDirEntry.java       |   56 -
 .../master/rest/TavernaServerDirectoryREST.java |  240 ---
 .../master/rest/TavernaServerInputREST.java     |  355 ----
 .../master/rest/TavernaServerListenersREST.java |  428 -----
 .../server/master/rest/TavernaServerREST.java   |  604 -------
 .../master/rest/TavernaServerRunREST.java       |  797 ---------
 .../master/rest/TavernaServerSecurityREST.java  |  775 ---------
 .../rest/handler/AccessDeniedHandler.java       |   21 -
 .../rest/handler/BadInputPortNameHandler.java   |   23 -
 .../rest/handler/BadPropertyValueHandler.java   |   23 -
 .../rest/handler/BadStateChangeHandler.java     |   23 -
 .../master/rest/handler/EntryHandler.java       |  131 --
 .../server/master/rest/handler/FeedHandler.java |   66 -
 .../rest/handler/FileConcatenationHandler.java  |   61 -
 .../master/rest/handler/FileMessageHandler.java |   80 -
 .../master/rest/handler/FileSegmentHandler.java |   74 -
 .../rest/handler/FilesystemAccessHandler.java   |   23 -
 .../rest/handler/GeneralFailureHandler.java     |   21 -
 .../server/master/rest/handler/HandlerCore.java |   71 -
 .../rest/handler/IllegalArgumentHandler.java    |   21 -
 .../handler/ImplementationProblemHandler.java   |   21 -
 .../rest/handler/InputStreamMessageHandler.java |  107 --
 .../rest/handler/InvalidCredentialHandler.java  |   23 -
 .../rest/handler/JAXBExceptionHandler.java      |   22 -
 .../rest/handler/NegotiationFailedHandler.java  |   25 -
 .../master/rest/handler/NoCreateHandler.java    |   23 -
 .../rest/handler/NoCredentialHandler.java       |   21 -
 .../master/rest/handler/NoDestroyHandler.java   |   23 -
 .../rest/handler/NoDirectoryEntryHandler.java   |   23 -
 .../master/rest/handler/NoListenerHandler.java  |   23 -
 .../master/rest/handler/NoUpdateHandler.java    |   23 -
 .../master/rest/handler/NotOwnerHandler.java    |   21 -
 .../master/rest/handler/OverloadedHandler.java  |   22 -
 .../master/rest/handler/PermissionHandler.java  |   74 -
 .../rest/handler/Scufl2DocumentHandler.java     |   87 -
 .../rest/handler/T2FlowDocumentHandler.java     |  118 --
 .../master/rest/handler/URIListHandler.java     |  121 --
 .../master/rest/handler/UnknownRunHandler.java  |   23 -
 .../master/rest/handler/ZipStreamHandler.java   |   54 -
 .../master/rest/handler/package-info.java       |   31 -
 .../server/master/rest/package-info.java        |   31 -
 .../taverna/server/master/soap/DirEntry.java    |  100 --
 .../server/master/soap/FileContents.java        |  171 --
 .../server/master/soap/PermissionList.java      |   50 -
 .../server/master/soap/TavernaServerSOAP.java   | 1553 ------------------
 .../server/master/soap/WrappedWorkflow.java     |  156 --
 .../server/master/soap/ZippedDirectory.java     |   89 -
 .../server/master/soap/package-info.java        |   31 -
 .../server/master/usage/UsageRecord.java        |  118 --
 .../master/usage/UsageRecordRecorder.java       |  163 --
 .../server/master/usage/package-info.java       |    9 -
 .../server/master/utils/CallTimeLogger.java     |   87 -
 .../server/master/utils/CallTimingFilter.java   |   65 -
 .../server/master/utils/CapabilityLister.java   |   44 -
 .../master/utils/CertificateChainFetcher.java   |  199 ---
 .../server/master/utils/Contextualizer.java     |   66 -
 .../taverna/server/master/utils/DerbyUtils.java |   68 -
 .../server/master/utils/FilenameUtils.java      |  268 ---
 .../utils/FlushThreadLocalCacheInterceptor.java |   18 -
 .../server/master/utils/InvocationCounter.java  |   48 -
 .../taverna/server/master/utils/JCECheck.java   |   60 -
 .../taverna/server/master/utils/JDOSupport.java |  270 ---
 .../master/utils/LoggingDerbyAdapter.java       |  138 --
 .../server/master/utils/OneShotThread.java      |   10 -
 .../taverna/server/master/utils/RestUtils.java  |   32 -
 .../master/utils/RuntimeExceptionWrapper.java   |   37 -
 .../server/master/utils/UsernamePrincipal.java  |   69 -
 .../utils/WSDLHeadOptionsInterceptor.java       |   65 -
 .../master/utils/WebappAwareDataSource.java     |  134 --
 .../taverna/server/master/utils/X500Utils.java  |  107 --
 .../server/master/utils/package-info.java       |   10 -
 .../master/worker/CompletionNotifier.java       |   45 -
 .../server/master/worker/FactoryBean.java       |   26 -
 .../server/master/worker/PasswordIssuer.java    |   57 -
 .../server/master/worker/PolicyImpl.java        |  158 --
 .../server/master/worker/PolicyLimits.java      |   43 -
 .../server/master/worker/RemoteRunDelegate.java |  967 -----------
 .../server/master/worker/RunConnection.java     |  239 ---
 .../server/master/worker/RunDBSupport.java      |   83 -
 .../server/master/worker/RunDatabase.java       |  311 ----
 .../server/master/worker/RunDatabaseDAO.java    |  306 ----
 .../master/worker/RunFactoryConfiguration.java  |  395 -----
 .../master/worker/SecurityContextDelegate.java  |  649 --------
 .../worker/SecurityContextDelegateImpl.java     |  298 ----
 .../master/worker/SecurityContextFactory.java   |  154 --
 .../SimpleFormattedCompletionNotifier.java      |   64 -
 .../worker/VelocityCompletionNotifier.java      |  105 --
 .../server/master/worker/WorkerModel.java       |  203 ---
 .../server/master/worker/package-info.java      |   10 -
 .../main/replacementscripts/executeworkflow.bat |   25 -
 .../main/replacementscripts/executeworkflow.sh  |   72 -
 server-webapp/src/main/resources/admin.html     |  240 ---
 .../src/main/resources/capabilities.properties  |   38 -
 .../src/main/resources/log4j.properties         |   39 -
 .../src/main/resources/security.policy          |    3 -
 .../src/main/resources/static/admin.js          |  549 -------
 .../main/resources/static/jquery-1.8.0.min.js   |    2 -
 .../static/jquery-ui-1.8.23.custom.css          |  563 -------
 .../static/jquery-ui-1.8.23.custom.min.js       |  125 --
 .../src/main/resources/static/t2cogs.png        |  Bin 135202 -> 0 bytes
 .../ui-bg_diagonals-small_25_c5ddfc_40x40.png   |  Bin 194 -> 0 bytes
 .../ui-bg_diagonals-thick_20_e69700_40x40.png   |  Bin 257 -> 0 bytes
 .../ui-bg_diagonals-thick_22_1484e6_40x40.png   |  Bin 384 -> 0 bytes
 .../ui-bg_diagonals-thick_26_2293f7_40x40.png   |  Bin 259 -> 0 bytes
 .../static/ui-bg_flat_0_e69700_40x100.png       |  Bin 181 -> 0 bytes
 .../static/ui-bg_flat_0_e6b900_40x100.png       |  Bin 212 -> 0 bytes
 .../ui-bg_highlight-soft_100_f9f9f9_1x100.png   |  Bin 88 -> 0 bytes
 .../ui-bg_inset-hard_100_eeeeee_1x100.png       |  Bin 91 -> 0 bytes
 .../static/ui-icons_0a82eb_256x240.png          |  Bin 4369 -> 0 bytes
 .../static/ui-icons_0b54d5_256x240.png          |  Bin 4369 -> 0 bytes
 .../static/ui-icons_5fa5e3_256x240.png          |  Bin 5355 -> 0 bytes
 .../static/ui-icons_fcdd4a_256x240.png          |  Bin 4369 -> 0 bytes
 .../static/ui-icons_ffffff_256x240.png          |  Bin 4369 -> 0 bytes
 .../src/main/resources/version.properties       |    5 -
 server-webapp/src/main/resources/welcome.html   |  122 --
 .../src/main/webapp/META-INF/MANIFEST.MF        |    3 -
 .../webapp/META-INF/cxf/org.apache.cxf.Logger   |    1 -
 .../src/main/webapp/META-INF/persistence.xml    |   14 -
 server-webapp/src/main/webapp/WEB-INF/beans.xml |  518 ------
 .../src/main/webapp/WEB-INF/insecure.xml        |   32 -
 ...orker.VelocityCompletionNotifier_email.vtmpl |   15 -
 ....worker.VelocityCompletionNotifier_sms.vtmpl |    1 -
 ...ker.VelocityCompletionNotifier_twitter.vtmpl |    1 -
 .../src/main/webapp/WEB-INF/partsecure.xml      |   36 -
 .../src/main/webapp/WEB-INF/providers.xml       |   96 --
 .../src/main/webapp/WEB-INF/secure.xml          |   35 -
 .../webapp/WEB-INF/security/users.properties    |   48 -
 .../webapp/WEB-INF/tavernaserver.properties     |   77 -
 .../src/main/webapp/WEB-INF/web-nosec.xml       |   79 -
 .../src/main/webapp/WEB-INF/web-partsec.xml     |   79 -
 .../src/main/webapp/WEB-INF/web-sec.xml         |   79 -
 .../src/main/webapp/WEB-INF/webappBeans.xml     |  213 ---
 server-webapp/src/misc/xsd/persistence_1_0.xsd  |  305 ----
 .../taverna/server/master/JaxbSanityTest.java   |  357 ----
 .../server/master/TavernaServerImplTest.java    |  246 ---
 .../master/WorkflowSerializationTest.java       |   68 -
 .../taverna/server/master/mocks/ExampleRun.java |  452 -----
 .../taverna/server/master/mocks/MockPolicy.java |   59 -
 .../master/mocks/SimpleListenerFactory.java     |   64 -
 .../mocks/SimpleNonpersistentRunStore.java      |  151 --
 .../server/master/mocks/SimpleServerPolicy.java |  110 --
 server-webapp/src/test/resources/example.xml    |   55 -
 .../src/test/resources/log4j.properties         |    4 -
 server-worker/pom.xml                           |  125 --
 .../src/main/java/META-INF/MANIFEST.MF          |    3 -
 .../server/localworker/api/Constants.java       |  141 --
 .../server/localworker/api/RunAccounting.java   |   22 -
 .../taverna/server/localworker/api/Worker.java  |  135 --
 .../server/localworker/api/WorkerFactory.java   |   18 -
 .../localworker/impl/DirectoryDelegate.java     |  161 --
 .../server/localworker/impl/FileDelegate.java   |  142 --
 .../server/localworker/impl/LocalWorker.java    |  769 ---------
 .../localworker/impl/TavernaRunManager.java     |  243 ---
 .../server/localworker/impl/WorkerCore.java     |  918 -----------
 .../impl/utils/FilenameVerifier.java            |  156 --
 .../localworker/impl/utils/TimingOutTask.java   |   40 -
 .../src/main/resources/security.policy          |   11 -
 .../localworker/impl/LocalWorkerTest.java       |  551 -------
 taverna-server-client/pom.xml                   |  130 ++
 .../uk/org/taverna/server/client/Connected.java |   20 +
 .../uk/org/taverna/server/client/DirEntry.java  |   39 +
 .../uk/org/taverna/server/client/Directory.java |   94 ++
 .../java/uk/org/taverna/server/client/File.java |   95 ++
 .../uk/org/taverna/server/client/Property.java  |   18 +
 .../java/uk/org/taverna/server/client/Run.java  |  215 +++
 .../uk/org/taverna/server/client/Status.java    |   36 +
 .../taverna/server/client/TavernaServer.java    |  128 ++
 .../client/TavernaServerConnectionFactory.java  |   23 +
 .../org/taverna/server/client/package-info.java |    5 +
 .../src/main/wadl/tavserv.wadl                  |  591 +++++++
 taverna-server-distribution/pom.xml             |  145 ++
 .../src/assemble/dist.xml                       |   82 +
 taverna-server-execution-delegate/pom.xml       |   41 +
 .../execution_delegate/ExecutionDelegate.java   |  172 ++
 .../execution_delegate/RemoteExecution.java     |  188 +++
 .../src/test/java/SerializationTest.java        |   54 +
 taverna-server-port-description/.gitignore      |    1 +
 taverna-server-port-description/pom.xml         |   45 +
 .../server/port_description/AbsentValue.java    |   13 +
 .../server/port_description/AbstractPort.java   |   26 +
 .../AbstractPortDescription.java                |   29 +
 .../server/port_description/AbstractValue.java  |   32 +
 .../server/port_description/ErrorValue.java     |   25 +
 .../port_description/InputDescription.java      |   51 +
 .../server/port_description/LeafValue.java      |   19 +
 .../server/port_description/ListValue.java      |   32 +
 .../server/port_description/Namespaces.java     |   12 +
 .../port_description/OutputDescription.java     |   52 +
 .../server/port_description/package-info.java   |   19 +
 .../port_description/utils/IntAdapter.java      |   32 +
 .../server/port_description/JaxbSanityTest.java |   98 ++
 taverna-server-rmidaemon/pom.xml                |   61 +
 .../org/taverna/server/rmidaemon/Registry.java  |   72 +
 .../taverna/server/rmidaemon/package-info.java  |    5 +
 taverna-server-runinterface/.gitignore          |    1 +
 taverna-server-runinterface/pom.xml             |   30 +
 .../src/main/java/META-INF/MANIFEST.MF          |    3 +
 .../remote/IllegalStateTransitionException.java |   36 +
 .../remote/ImplementationException.java         |   26 +
 .../localworker/remote/RemoteDirectory.java     |   62 +
 .../remote/RemoteDirectoryEntry.java            |   62 +
 .../server/localworker/remote/RemoteFile.java   |   98 ++
 .../server/localworker/remote/RemoteInput.java  |   92 ++
 .../localworker/remote/RemoteListener.java      |   77 +
 .../localworker/remote/RemoteRunFactory.java    |   84 +
 .../remote/RemoteSecurityContext.java           |   34 +
 .../localworker/remote/RemoteSingleRun.java     |  254 +++
 .../server/localworker/remote/RemoteStatus.java |   40 +
 .../remote/StillWorkingOnItException.java       |   20 +
 .../server/localworker/remote/package-info.java |    9 +
 .../localworker/server/UsageRecordReceiver.java |   29 +
 .../server/localworker/server/package-info.java |    9 +
 taverna-server-unix-forker/pom.xml              |   61 +
 .../org/taverna/server/unixforker/Forker.java   |  208 +++
 taverna-server-usagerecord/.gitignore           |    1 +
 taverna-server-usagerecord/pom.xml              |   79 +
 .../main/java/org/ogf/usage/JobUsageRecord.java |  304 ++++
 taverna-server-usagerecord/src/main/xsd/ur.xsd  |  425 +++++
 .../src/main/xsd/xmlds.xsd                      |  318 ++++
 .../src/test/java/TestUR.java                   |  120 ++
 taverna-server-webapp/.gitignore                |    1 +
 taverna-server-webapp/pom.xml                   |  889 ++++++++++
 .../resources/datanucleus_log4j.properties      |    4 +
 .../master/ContentsDescriptorBuilder.java       |  292 ++++
 .../taverna/server/master/DirectoryREST.java    |  375 +++++
 .../server/master/FileConcatenation.java        |   68 +
 .../org/taverna/server/master/InputREST.java    |  252 +++
 .../taverna/server/master/InteractionFeed.java  |  107 ++
 .../server/master/ListenerPropertyREST.java     |   78 +
 .../taverna/server/master/ListenersREST.java    |   93 ++
 .../taverna/server/master/ManagementState.java  |  215 +++
 .../java/org/taverna/server/master/RunREST.java |  499 ++++++
 .../taverna/server/master/RunSecurityREST.java  |  303 ++++
 .../server/master/SingleListenerREST.java       |   97 ++
 .../taverna/server/master/TavernaServer.java    | 1425 ++++++++++++++++
 .../server/master/TavernaServerSupport.java     |  957 +++++++++++
 .../org/taverna/server/master/admin/Admin.java  | 1100 +++++++++++++
 .../taverna/server/master/admin/AdminBean.java  |  794 +++++++++
 .../server/master/admin/package-info.java       |   33 +
 .../taverna/server/master/api/ContentTypes.java |   50 +
 .../server/master/api/DirectoryBean.java        |   16 +
 .../org/taverna/server/master/api/FeedBean.java |   13 +
 .../taverna/server/master/api/InputBean.java    |   21 +
 .../server/master/api/ListenerPropertyBean.java |   15 +
 .../server/master/api/ListenersBean.java        |   13 +
 .../server/master/api/ManagementModel.java      |   61 +
 .../server/master/api/OneListenerBean.java      |   14 +
 .../org/taverna/server/master/api/RunBean.java  |   17 +
 .../taverna/server/master/api/SecurityBean.java |   14 +
 .../taverna/server/master/api/SupportAware.java |   21 +
 .../server/master/api/TavernaServerBean.java    |  101 ++
 .../taverna/server/master/api/package-info.java |    6 +
 .../server/master/common/Capability.java        |   22 +
 .../server/master/common/Credential.java        |  149 ++
 .../server/master/common/DirEntryReference.java |   93 ++
 .../server/master/common/InputDescription.java  |  110 ++
 .../server/master/common/Namespaces.java        |   39 +
 .../server/master/common/Permission.java        |   43 +
 .../server/master/common/ProfileList.java       |   42 +
 .../org/taverna/server/master/common/Roles.java |   25 +
 .../server/master/common/RunReference.java      |   67 +
 .../taverna/server/master/common/Status.java    |   44 +
 .../org/taverna/server/master/common/Trust.java |   79 +
 .../org/taverna/server/master/common/Uri.java   |  432 +++++
 .../server/master/common/VersionedElement.java  |   65 +
 .../taverna/server/master/common/Workflow.java  |  367 +++++
 .../server/master/common/package-info.java      |   29 +
 .../server/master/common/version/Version.java   |   43 +
 .../taverna/server/master/defaults/Default.java |   99 ++
 .../server/master/defaults/package-info.java    |    5 +
 .../exceptions/BadInputPortNameException.java   |   21 +
 .../exceptions/BadPropertyValueException.java   |   26 +
 .../exceptions/BadStateChangeException.java     |   35 +
 .../exceptions/FilesystemAccessException.java   |   38 +
 .../exceptions/GeneralFailureException.java     |   28 +
 .../exceptions/InvalidCredentialException.java  |   36 +
 .../master/exceptions/NoCreateException.java    |   32 +
 .../exceptions/NoCredentialException.java       |   18 +
 .../master/exceptions/NoDestroyException.java   |   24 +
 .../exceptions/NoDirectoryEntryException.java   |   24 +
 .../master/exceptions/NoListenerException.java  |   33 +
 .../master/exceptions/NoUpdateException.java    |   33 +
 .../master/exceptions/NotOwnerException.java    |   23 +
 .../master/exceptions/OverloadedException.java  |   35 +
 .../master/exceptions/UnknownRunException.java  |   27 +
 .../server/master/exceptions/package-info.java  |   29 +
 .../taverna/server/master/facade/Facade.java    |   73 +
 .../server/master/facade/package-info.java      |   10 +
 .../factories/ConfigurableRunFactory.java       |  133 ++
 .../master/factories/ListenerFactory.java       |   46 +
 .../server/master/factories/RunFactory.java     |   40 +
 .../server/master/factories/package-info.java   |   10 +
 .../identity/AuthorityDerivedIDMapper.java      |   50 +
 .../master/identity/CompositeIDMapper.java      |   65 +
 .../master/identity/ConstantIDMapper.java       |   32 +
 .../server/master/identity/NameIDMapper.java    |   50 +
 .../identity/StrippedDownAuthProvider.java      |  278 ++++
 .../taverna/server/master/identity/User.java    |  153 ++
 .../server/master/identity/UserStore.java       |  389 +++++
 .../server/master/identity/UserStoreAPI.java    |   91 +
 .../identity/WorkflowInternalAuthProvider.java  |  304 ++++
 .../server/master/identity/package-info.java    |   10 +
 .../interaction/InteractionFeedSupport.java     |  316 ++++
 .../server/master/interaction/package-info.java |   10 +
 .../server/master/interfaces/Directory.java     |   82 +
 .../master/interfaces/DirectoryEntry.java       |   47 +
 .../taverna/server/master/interfaces/File.java  |   69 +
 .../taverna/server/master/interfaces/Input.java |   92 ++
 .../server/master/interfaces/Listener.java      |   64 +
 .../master/interfaces/LocalIdentityMapper.java  |   29 +
 .../master/interfaces/MessageDispatcher.java    |   45 +
 .../server/master/interfaces/Policy.java        |  120 ++
 .../server/master/interfaces/RunStore.java      |   82 +
 .../interfaces/SecurityContextFactory.java      |   32 +
 .../server/master/interfaces/TavernaRun.java    |  219 +++
 .../interfaces/TavernaSecurityContext.java      |  213 +++
 .../master/interfaces/UriBuilderFactory.java    |   43 +
 .../server/master/interfaces/package-info.java  |   10 +
 .../localworker/AbstractRemoteRunFactory.java   |  440 +++++
 .../master/localworker/ForkRunFactory.java      |  323 ++++
 .../localworker/IdAwareForkRunFactory.java      |  516 ++++++
 .../master/localworker/LocalWorkerFactory.java  |   31 +
 .../master/localworker/LocalWorkerState.java    |  454 +++++
 .../master/localworker/PersistedState.java      |  257 +++
 .../server/master/localworker/StreamLogger.java |   62 +
 .../server/master/localworker/package-info.java |   10 +
 .../master/notification/EmailDispatcher.java    |  113 ++
 .../master/notification/JabberDispatcher.java   |  140 ++
 .../master/notification/NotificationEngine.java |  145 ++
 .../notification/RateLimitedDispatcher.java     |   89 +
 .../master/notification/SMSDispatcher.java      |  158 ++
 .../master/notification/TwitterDispatcher.java  |  132 ++
 .../master/notification/atom/AtomFeed.java      |  134 ++
 .../server/master/notification/atom/Event.java  |  110 ++
 .../master/notification/atom/EventDAO.java      |  206 +++
 .../master/notification/atom/package-info.java  |   29 +
 .../master/notification/package-info.java       |   10 +
 .../org/taverna/server/master/package-info.java |   11 +
 .../server/master/rest/ContentTypes.java        |   28 +
 .../server/master/rest/DirectoryContents.java   |   61 +
 .../taverna/server/master/rest/FileSegment.java |   78 +
 .../server/master/rest/InteractionFeedREST.java |  126 ++
 .../server/master/rest/ListenerDefinition.java  |   32 +
 .../master/rest/MakeOrUpdateDirEntry.java       |   56 +
 .../master/rest/TavernaServerDirectoryREST.java |  240 +++
 .../master/rest/TavernaServerInputREST.java     |  355 ++++
 .../master/rest/TavernaServerListenersREST.java |  428 +++++
 .../server/master/rest/TavernaServerREST.java   |  604 +++++++
 .../master/rest/TavernaServerRunREST.java       |  797 +++++++++
 .../master/rest/TavernaServerSecurityREST.java  |  775 +++++++++
 .../rest/handler/AccessDeniedHandler.java       |   21 +
 .../rest/handler/BadInputPortNameHandler.java   |   23 +
 .../rest/handler/BadPropertyValueHandler.java   |   23 +
 .../rest/handler/BadStateChangeHandler.java     |   23 +
 .../master/rest/handler/EntryHandler.java       |  131 ++
 .../server/master/rest/handler/FeedHandler.java |   66 +
 .../rest/handler/FileConcatenationHandler.java  |   61 +
 .../master/rest/handler/FileMessageHandler.java |   80 +
 .../master/rest/handler/FileSegmentHandler.java |   74 +
 .../rest/handler/FilesystemAccessHandler.java   |   23 +
 .../rest/handler/GeneralFailureHandler.java     |   21 +
 .../server/master/rest/handler/HandlerCore.java |   71 +
 .../rest/handler/IllegalArgumentHandler.java    |   21 +
 .../handler/ImplementationProblemHandler.java   |   21 +
 .../rest/handler/InputStreamMessageHandler.java |  107 ++
 .../rest/handler/InvalidCredentialHandler.java  |   23 +
 .../rest/handler/JAXBExceptionHandler.java      |   22 +
 .../rest/handler/NegotiationFailedHandler.java  |   25 +
 .../master/rest/handler/NoCreateHandler.java    |   23 +
 .../rest/handler/NoCredentialHandler.java       |   21 +
 .../master/rest/handler/NoDestroyHandler.java   |   23 +
 .../rest/handler/NoDirectoryEntryHandler.java   |   23 +
 .../master/rest/handler/NoListenerHandler.java  |   23 +
 .../master/rest/handler/NoUpdateHandler.java    |   23 +
 .../master/rest/handler/NotOwnerHandler.java    |   21 +
 .../master/rest/handler/OverloadedHandler.java  |   22 +
 .../master/rest/handler/PermissionHandler.java  |   74 +
 .../rest/handler/Scufl2DocumentHandler.java     |   87 +
 .../rest/handler/T2FlowDocumentHandler.java     |  118 ++
 .../master/rest/handler/URIListHandler.java     |  121 ++
 .../master/rest/handler/UnknownRunHandler.java  |   23 +
 .../master/rest/handler/ZipStreamHandler.java   |   54 +
 .../master/rest/handler/package-info.java       |   31 +
 .../server/master/rest/package-info.java        |   31 +
 .../taverna/server/master/soap/DirEntry.java    |  100 ++
 .../server/master/soap/FileContents.java        |  171 ++
 .../server/master/soap/PermissionList.java      |   50 +
 .../server/master/soap/TavernaServerSOAP.java   | 1553 ++++++++++++++++++
 .../server/master/soap/WrappedWorkflow.java     |  156 ++
 .../server/master/soap/ZippedDirectory.java     |   89 +
 .../server/master/soap/package-info.java        |   31 +
 .../server/master/usage/UsageRecord.java        |  118 ++
 .../master/usage/UsageRecordRecorder.java       |  163 ++
 .../server/master/usage/package-info.java       |    9 +
 .../server/master/utils/CallTimeLogger.java     |   87 +
 .../server/master/utils/CallTimingFilter.java   |   65 +
 .../server/master/utils/CapabilityLister.java   |   44 +
 .../master/utils/CertificateChainFetcher.java   |  199 +++
 .../server/master/utils/Contextualizer.java     |   66 +
 .../taverna/server/master/utils/DerbyUtils.java |   68 +
 .../server/master/utils/FilenameUtils.java      |  268 +++
 .../utils/FlushThreadLocalCacheInterceptor.java |   18 +
 .../server/master/utils/InvocationCounter.java  |   48 +
 .../taverna/server/master/utils/JCECheck.java   |   60 +
 .../taverna/server/master/utils/JDOSupport.java |  270 +++
 .../master/utils/LoggingDerbyAdapter.java       |  138 ++
 .../server/master/utils/OneShotThread.java      |   10 +
 .../taverna/server/master/utils/RestUtils.java  |   32 +
 .../master/utils/RuntimeExceptionWrapper.java   |   37 +
 .../server/master/utils/UsernamePrincipal.java  |   69 +
 .../utils/WSDLHeadOptionsInterceptor.java       |   65 +
 .../master/utils/WebappAwareDataSource.java     |  134 ++
 .../taverna/server/master/utils/X500Utils.java  |  107 ++
 .../server/master/utils/package-info.java       |   10 +
 .../master/worker/CompletionNotifier.java       |   45 +
 .../server/master/worker/FactoryBean.java       |   26 +
 .../server/master/worker/PasswordIssuer.java    |   57 +
 .../server/master/worker/PolicyImpl.java        |  158 ++
 .../server/master/worker/PolicyLimits.java      |   43 +
 .../server/master/worker/RemoteRunDelegate.java |  967 +++++++++++
 .../server/master/worker/RunConnection.java     |  239 +++
 .../server/master/worker/RunDBSupport.java      |   83 +
 .../server/master/worker/RunDatabase.java       |  311 ++++
 .../server/master/worker/RunDatabaseDAO.java    |  306 ++++
 .../master/worker/RunFactoryConfiguration.java  |  395 +++++
 .../master/worker/SecurityContextDelegate.java  |  649 ++++++++
 .../worker/SecurityContextDelegateImpl.java     |  298 ++++
 .../master/worker/SecurityContextFactory.java   |  154 ++
 .../SimpleFormattedCompletionNotifier.java      |   64 +
 .../worker/VelocityCompletionNotifier.java      |  105 ++
 .../server/master/worker/WorkerModel.java       |  203 +++
 .../server/master/worker/package-info.java      |   10 +
 .../main/replacementscripts/executeworkflow.bat |   25 +
 .../main/replacementscripts/executeworkflow.sh  |   72 +
 .../src/main/resources/admin.html               |  240 +++
 .../src/main/resources/capabilities.properties  |   38 +
 .../src/main/resources/log4j.properties         |   39 +
 .../src/main/resources/security.policy          |    3 +
 .../src/main/resources/static/admin.js          |  549 +++++++
 .../main/resources/static/jquery-1.8.0.min.js   |    2 +
 .../static/jquery-ui-1.8.23.custom.css          |  563 +++++++
 .../static/jquery-ui-1.8.23.custom.min.js       |  125 ++
 .../src/main/resources/static/t2cogs.png        |  Bin 0 -> 135202 bytes
 .../ui-bg_diagonals-small_25_c5ddfc_40x40.png   |  Bin 0 -> 194 bytes
 .../ui-bg_diagonals-thick_20_e69700_40x40.png   |  Bin 0 -> 257 bytes
 .../ui-bg_diagonals-thick_22_1484e6_40x40.png   |  Bin 0 -> 384 bytes
 .../ui-bg_diagonals-thick_26_2293f7_40x40.png   |  Bin 0 -> 259 bytes
 .../static/ui-bg_flat_0_e69700_40x100.png       |  Bin 0 -> 181 bytes
 .../static/ui-bg_flat_0_e6b900_40x100.png       |  Bin 0 -> 212 bytes
 .../ui-bg_highlight-soft_100_f9f9f9_1x100.png   |  Bin 0 -> 88 bytes
 .../ui-bg_inset-hard_100_eeeeee_1x100.png       |  Bin 0 -> 91 bytes
 .../static/ui-icons_0a82eb_256x240.png          |  Bin 0 -> 4369 bytes
 .../static/ui-icons_0b54d5_256x240.png          |  Bin 0 -> 4369 bytes
 .../static/ui-icons_5fa5e3_256x240.png          |  Bin 0 -> 5355 bytes
 .../static/ui-icons_fcdd4a_256x240.png          |  Bin 0 -> 4369 bytes
 .../static/ui-icons_ffffff_256x240.png          |  Bin 0 -> 4369 bytes
 .../src/main/resources/version.properties       |    5 +
 .../src/main/resources/welcome.html             |  122 ++
 .../src/main/webapp/META-INF/MANIFEST.MF        |    3 +
 .../webapp/META-INF/cxf/org.apache.cxf.Logger   |    1 +
 .../src/main/webapp/META-INF/persistence.xml    |   14 +
 .../src/main/webapp/WEB-INF/beans.xml           |  518 ++++++
 .../src/main/webapp/WEB-INF/insecure.xml        |   32 +
 ...orker.VelocityCompletionNotifier_email.vtmpl |   15 +
 ....worker.VelocityCompletionNotifier_sms.vtmpl |    1 +
 ...ker.VelocityCompletionNotifier_twitter.vtmpl |    1 +
 .../src/main/webapp/WEB-INF/partsecure.xml      |   36 +
 .../src/main/webapp/WEB-INF/providers.xml       |   96 ++
 .../src/main/webapp/WEB-INF/secure.xml          |   35 +
 .../webapp/WEB-INF/security/users.properties    |   48 +
 .../webapp/WEB-INF/tavernaserver.properties     |   77 +
 .../src/main/webapp/WEB-INF/web-nosec.xml       |   79 +
 .../src/main/webapp/WEB-INF/web-partsec.xml     |   79 +
 .../src/main/webapp/WEB-INF/web-sec.xml         |   79 +
 .../src/main/webapp/WEB-INF/webappBeans.xml     |  213 +++
 .../src/misc/xsd/persistence_1_0.xsd            |  305 ++++
 .../taverna/server/master/JaxbSanityTest.java   |  357 ++++
 .../server/master/TavernaServerImplTest.java    |  246 +++
 .../master/WorkflowSerializationTest.java       |   68 +
 .../taverna/server/master/mocks/ExampleRun.java |  452 +++++
 .../taverna/server/master/mocks/MockPolicy.java |   59 +
 .../master/mocks/SimpleListenerFactory.java     |   64 +
 .../mocks/SimpleNonpersistentRunStore.java      |  151 ++
 .../server/master/mocks/SimpleServerPolicy.java |  110 ++
 .../src/test/resources/example.xml              |   55 +
 .../src/test/resources/log4j.properties         |    4 +
 taverna-server-worker/pom.xml                   |  125 ++
 .../src/main/java/META-INF/MANIFEST.MF          |    3 +
 .../server/localworker/api/Constants.java       |  141 ++
 .../server/localworker/api/RunAccounting.java   |   22 +
 .../taverna/server/localworker/api/Worker.java  |  135 ++
 .../server/localworker/api/WorkerFactory.java   |   18 +
 .../localworker/impl/DirectoryDelegate.java     |  161 ++
 .../server/localworker/impl/FileDelegate.java   |  142 ++
 .../server/localworker/impl/LocalWorker.java    |  769 +++++++++
 .../localworker/impl/TavernaRunManager.java     |  243 +++
 .../server/localworker/impl/WorkerCore.java     |  918 +++++++++++
 .../impl/utils/FilenameVerifier.java            |  156 ++
 .../localworker/impl/utils/TimingOutTask.java   |   40 +
 .../src/main/resources/security.policy          |   11 +
 .../localworker/impl/LocalWorkerTest.java       |  551 +++++++
 688 files changed, 43826 insertions(+), 43885 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 4240e5d..850b30b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -412,16 +412,16 @@ executing.</description>
 	</profiles>
 
 	<modules>
-		<module>server-webapp</module>
-		<module>server-runinterface</module>
-		<module>server-worker</module>
-		<module>server-unix-forker</module>
-		<module>server-usagerecord</module>
-		<module>server-port-description</module>
-		<module>server-execution-delegate</module>
-		<module>server-rmidaemon</module>
-		<module>server-client</module>
-		<module>server-distribution</module>
+		<module>taverna-server-webapp</module>
+		<module>taverna-server-runinterface</module>
+		<module>taverna-server-worker</module>
+		<module>taverna-server-unix-forker</module>
+		<module>taverna-server-usagerecord</module>
+		<module>taverna-server-port-description</module>
+		<module>taverna-server-execution-delegate</module>
+		<module>taverna-server-rmidaemon</module>
+		<module>taverna-server-client</module>
+		<module>taverna-server-distribution</module>
 	</modules>
 
   <scm>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/pom.xml
----------------------------------------------------------------------
diff --git a/server-client/pom.xml b/server-client/pom.xml
deleted file mode 100644
index d16b07a..0000000
--- a/server-client/pom.xml
+++ /dev/null
@@ -1,130 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-client</artifactId>
-	<packaging>bundle</packaging>
-	<name>Apache Taverna Server Client OSGi Module</name>
-
-	<dependencies>
-		<dependency>
-			<groupId>org.jvnet.ws.wadl</groupId>
-			<artifactId>wadl-core</artifactId>
-			<version>1.1.6</version>
-		</dependency>
-		<dependency>
-			<groupId>com.sun.jersey</groupId>
-			<artifactId>jersey-client</artifactId>
-			<version>1.8</version>
-		</dependency>
-		<dependency>
-			<groupId>commons-io</groupId>
-			<artifactId>commons-io</artifactId>
-			<version>2.4</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.tika</groupId>
-			<artifactId>tika-core</artifactId>
-			<version>1.5</version>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-usagerecord</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-	</dependencies>
-
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.felix</groupId>
-				<artifactId>maven-bundle-plugin</artifactId>
-				<extensions>true</extensions>
-				<configuration>
-					<instructions>
-						<Export-Package>uk.org.taverna.server.client</Export-Package>
-						<Private-Package>uk.org.taverna.server.client.*</Private-Package>
-					</instructions>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.jvnet.ws.wadl</groupId>
-				<artifactId>wadl-client-plugin</artifactId>
-				<version>1.1.6</version>
-				<executions>
-					<execution>
-						<goals>
-							<goal>generate</goal>
-						</goals>
-					</execution>
-				</executions>
-				<configuration>
-					<packageName>org.taverna.server.client.wadl</packageName>
-					<includes>*.wadl</includes>
-					<customClassNames>
-						<property>
-							<name>http://example.com/taverna/rest</name>
-							<value>TavernaServer</value>
-						</property>
-					</customClassNames>
-				</configuration>
-			</plugin>
-		</plugins>
-		<pluginManagement>
-			<plugins>
-				<!--This plugin's configuration is used to store Eclipse m2e settings
-					only. It has no influence on the Maven build itself. -->
-				<plugin>
-					<groupId>org.eclipse.m2e</groupId>
-					<artifactId>lifecycle-mapping</artifactId>
-					<version>1.0.0</version>
-					<configuration>
-						<lifecycleMappingMetadata>
-							<pluginExecutions>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>
-											org.jvnet.ws.wadl
-										</groupId>
-										<artifactId>
-											wadl-client-plugin
-										</artifactId>
-										<versionRange>
-											[1.1.6,)
-										</versionRange>
-										<goals>
-											<goal>generate</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute />
-									</action>
-								</pluginExecution>
-							</pluginExecutions>
-						</lifecycleMappingMetadata>
-					</configuration>
-				</plugin>
-			</plugins>
-		</pluginManagement>
-	</build>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/Connected.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/Connected.java b/server-client/src/main/java/uk/org/taverna/server/client/Connected.java
deleted file mode 100644
index 263034c..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/Connected.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package uk.org.taverna.server.client;
-
-import uk.org.taverna.server.client.TavernaServer.ClientException;
-import uk.org.taverna.server.client.TavernaServer.ServerException;
-
-import com.sun.jersey.api.client.ClientResponse;
-
-abstract class Connected {
-	void checkError(ClientResponse response) throws ClientException,
-			ServerException {
-		ClientResponse.Status s = response.getClientResponseStatus();
-		if (s.getStatusCode() == 401)
-			throw new TavernaServer.AuthorizationException("not authorized",
-					null);
-		if (s.getStatusCode() >= 500)
-			throw new TavernaServer.ServerException(s.getReasonPhrase(), null);
-		if (s.getStatusCode() >= 400)
-			throw new TavernaServer.ClientException(s.getReasonPhrase(), null);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java b/server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
deleted file mode 100644
index 267707d..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/DirEntry.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package uk.org.taverna.server.client;
-
-import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd.Path2;
-
-import uk.org.taverna.server.client.TavernaServer.ClientException;
-import uk.org.taverna.server.client.TavernaServer.ServerException;
-
-import com.sun.jersey.api.client.ClientResponse;
-
-public abstract class DirEntry extends Connected {
-	final Path2 handle;
-	final String path;
-	final Run run;
-
-	protected DirEntry(Run run, String path) {
-		this.run = run;
-		this.path = path.replaceFirst("/+$", "");
-		this.handle = run.run.wd().path2(this.path);
-	}
-
-	public void delete() throws ClientException, ServerException {
-		checkError(handle.deleteAsXml(ClientResponse.class));
-	}
-
-	String path(ClientResponse response) throws ClientException, ServerException {
-		checkError(response);
-		String[] bits = response.getLocation().getPath().split("/");
-		return concat(bits[bits.length - 1]);
-	}
-
-	String localName() {
-		String[] bits = path.split("/");
-		return bits[bits.length - 1];
-	}
-
-	String concat(String name) {
-		return path + "/" + name.split("/", 2)[0];
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/Directory.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/Directory.java b/server-client/src/main/java/uk/org/taverna/server/client/Directory.java
deleted file mode 100644
index 38dc394..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/Directory.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package uk.org.taverna.server.client;
-
-import static java.io.File.createTempFile;
-import static javax.ws.rs.client.Entity.entity;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipFile;
-
-import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
-
-import uk.org.taverna.server.client.TavernaServer.ClientException;
-import uk.org.taverna.server.client.TavernaServer.ServerException;
-import uk.org.taverna.server.client.generic.DirectoryEntry;
-import uk.org.taverna.server.client.generic.DirectoryReference;
-import uk.org.taverna.server.client.generic.FileReference;
-import uk.org.taverna.server.client.rest.DirectoryContents;
-import uk.org.taverna.server.client.rest.MakeDirectory;
-import uk.org.taverna.server.client.rest.UploadFile;
-
-import com.sun.jersey.api.client.ClientResponse;
-
-public class Directory extends DirEntry {
-	private final Wd wd;
-
-	Directory(Run run) {
-		super(run, "");
-		this.wd = run.run.wd();
-	}
-
-	Directory(Run run, String path) {
-		super(run, path);
-		this.wd = run.run.wd();
-	}
-
-	public List<DirEntry> list() {
-		List<DirEntry> result = new ArrayList<>();
-		for (DirectoryEntry de : wd.path3(path)
-				.getAsXml(DirectoryContents.class).getDirOrFile())
-			if (de instanceof DirectoryReference)
-				result.add(new Directory(run, de.getValue()));
-			else if (de instanceof FileReference)
-				result.add(new File(run, de.getValue()));
-		return result;
-	}
-
-	public File createFile(String name, byte[] content) throws ClientException,
-			ServerException {
-		UploadFile uf = new UploadFile();
-		uf.setName(name);
-		uf.setValue(content);
-		return new File(run, path(wd.path(path).putAsXml(uf,
-				ClientResponse.class)));
-	}
-
-	public File createFile(String name, java.io.File content)
-			throws ClientException, ServerException {
-		return new File(run, path(wd.path(concat(name)).putOctetStreamAsXml(
-				entity(content, APPLICATION_OCTET_STREAM_TYPE),
-				ClientResponse.class)));
-	}
-
-	public File createFile(String name, URI source) throws ClientException,
-			ServerException {
-		return new File(run, path(wd.path(concat(name)).postTextUriListAsXml(
-				source.toString(), ClientResponse.class)));
-	}
-
-	public Directory createDirectory(String name) throws ClientException,
-			ServerException {
-		MakeDirectory mkdir = new MakeDirectory();
-		mkdir.setName(name);
-		return new Directory(run, path(wd.path(path).putAsXml(mkdir,
-				ClientResponse.class)));
-	}
-
-	public byte[] getZippedContents() {
-		return wd.path3(path).getAsZip(byte[].class);
-	}
-
-	public ZipFile getZip() throws IOException {
-		byte[] contents = getZippedContents();
-		java.io.File tmp = createTempFile(localName(), ".zip");
-		try (OutputStream os = new FileOutputStream(tmp)) {
-			os.write(contents);
-		}
-		return new ZipFile(tmp);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/File.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/File.java b/server-client/src/main/java/uk/org/taverna/server/client/File.java
deleted file mode 100644
index 0287afb..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/File.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package uk.org.taverna.server.client;
-
-import static java.io.File.createTempFile;
-import static javax.ws.rs.client.Entity.entity;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-import static org.apache.commons.io.IOUtils.copy;
-import static org.apache.tika.mime.MimeTypes.getDefaultMimeTypes;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-
-import org.apache.tika.mime.MimeTypeException;
-import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName.Wd;
-
-import uk.org.taverna.server.client.TavernaServer.ClientException;
-import uk.org.taverna.server.client.TavernaServer.ServerException;
-
-import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.UniformInterfaceException;
-
-public class File extends DirEntry {
-	private final Wd wd;
-
-	File(Run run, String path) {
-		super(run, path);
-		wd = run.run.wd();
-	}
-
-	public InputStream getAsStream() {
-		return wd.path3(path).getAsOctetStream(InputStream.class);
-	}
-
-	public byte[] get() {
-		return wd.path3(path).getAsOctetStream(byte[].class);
-	}
-
-	public String get(Charset encoding) {
-		return new String(wd.path3(path).getAsOctetStream(byte[].class),
-				encoding);
-	}
-
-	public java.io.File getAsFile() throws ClientHandlerException,
-			UniformInterfaceException, IOException, MimeTypeException,
-			ClientException, ServerException {
-		ClientResponse cr = wd.path3(path).getAsOctetStream(
-				ClientResponse.class);
-		checkError(cr);
-		String[] bits = localName().split("[.]");
-		String ext = getDefaultMimeTypes().forName(
-				cr.getHeaders().getFirst("Content-Type")).getExtension();
-		if (ext == null)
-			ext = bits[bits.length - 1];
-		java.io.File tmp = createTempFile(bits[0], ext);
-		try (OutputStream os = new FileOutputStream(tmp);
-				InputStream is = cr.getEntity(InputStream.class)) {
-			copy(is, os);
-		}
-		return tmp;
-	}
-
-	public void setContents(byte[] newContents) throws ClientException,
-			ServerException {
-		checkError(wd.path(path).putOctetStreamAsXml(newContents,
-				ClientResponse.class));
-	}
-
-	public void setContents(String newContents) throws ClientException,
-			ServerException {
-		checkError(wd.path(path).putOctetStreamAsXml(newContents,
-				ClientResponse.class));
-	}
-
-	public void setContents(String newContents, Charset encoding)
-			throws ClientException, ServerException {
-		checkError(wd.path(path).putOctetStreamAsXml(
-				newContents.getBytes(encoding), ClientResponse.class));
-	}
-
-	public void setContents(InputStream newContents) throws ClientException,
-			ServerException {
-		checkError(wd.path(path).putOctetStreamAsXml(newContents,
-				ClientResponse.class));
-	}
-
-	public void setContents(java.io.File newContents) throws IOException,
-			ClientException, ServerException {
-		checkError(wd.path(path).putOctetStreamAsXml(
-				entity(newContents, APPLICATION_OCTET_STREAM_TYPE),
-				ClientResponse.class));
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/Property.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/Property.java b/server-client/src/main/java/uk/org/taverna/server/client/Property.java
deleted file mode 100644
index 0e6542f..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/Property.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package uk.org.taverna.server.client;
-
-public enum Property {
-	STDOUT("stdout"), STDERR("stderr"), EXIT_CODE("exitcode"), READY_TO_NOTIFY(
-			"readyToNotify"), EMAIL("notificationAddress"), USAGE(
-			"usageRecord");
-
-	private String s;
-
-	private Property(String s) {
-		this.s = s;
-	}
-
-	@Override
-	public String toString() {
-		return s;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/Run.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/Run.java b/server-client/src/main/java/uk/org/taverna/server/client/Run.java
deleted file mode 100644
index 5c6875e..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/Run.java
+++ /dev/null
@@ -1,215 +0,0 @@
-package uk.org.taverna.server.client;
-
-import static org.joda.time.format.ISODateTimeFormat.dateTime;
-import static org.joda.time.format.ISODateTimeFormat.dateTimeParser;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.Date;
-import java.util.List;
-
-import javax.xml.bind.JAXBException;
-
-import org.apache.commons.io.IOUtils;
-import org.joda.time.DateTime;
-import org.ogf.usage.JobUsageRecord;
-import org.taverna.server.client.wadl.TavernaServer.Root.RunsRunName;
-import org.w3c.dom.Element;
-
-import uk.org.taverna.server.client.TavernaServer.ClientException;
-import uk.org.taverna.server.client.TavernaServer.ServerException;
-import uk.org.taverna.server.client.generic.KeyPairCredential;
-import uk.org.taverna.server.client.generic.PasswordCredential;
-import uk.org.taverna.server.client.generic.port.InputPort;
-import uk.org.taverna.server.client.generic.port.OutputPort;
-import uk.org.taverna.server.client.rest.InputDescription;
-import uk.org.taverna.server.client.rest.InputDescription.Value;
-
-import com.sun.jersey.api.client.ClientResponse;
-
-public class Run extends Connected {
-	RunsRunName run;
-
-	Run(TavernaServer server, String value) {
-		run = server.root.runsRunName(value);
-	}
-
-	public String getName() {
-		return run.name().getAsTextPlain(ClientResponse.class)
-				.getEntity(String.class);
-	}
-
-	public void setName(String name) {
-		run.name().putTextPlain(name, String.class);
-	}
-
-	public Date getExpiry() {
-		return dateTimeParser().parseDateTime(
-				run.expiry().getAsTextPlain(String.class)).toDate();
-	}
-
-	public void setExpiry(Date expiryTimestamp) {
-		run.expiry().putTextPlain(
-				dateTime().print(new DateTime(expiryTimestamp)), String.class);
-	}
-
-	public Date getCreate() {
-		String timestamp = run.createTime().getAsTextPlain(String.class);
-		if (timestamp == null || timestamp.trim().isEmpty())
-			return null;
-		return dateTimeParser().parseDateTime(timestamp).toDate();
-	}
-
-	public Date getStart() {
-		String timestamp = run.startTime().getAsTextPlain(String.class);
-		if (timestamp == null || timestamp.trim().isEmpty())
-			return null;
-		return dateTimeParser().parseDateTime(timestamp).toDate();
-	}
-
-	public Date getFinish() {
-		String timestamp = run.finishTime().getAsTextPlain(String.class);
-		if (timestamp == null || timestamp.trim().isEmpty())
-			return null;
-		return dateTimeParser().parseDateTime(timestamp).toDate();
-	}
-
-	public Status getStatus() {
-		return Status.valueOf(run.status().getAsTextPlain(String.class));
-	}
-
-	public void setStatus(Status status) {
-		run.status().putTextPlain(status, String.class);
-	}
-
-	public void start() {
-		setStatus(Status.Operating);
-	}
-
-	public void kill() {
-		setStatus(Status.Finished);
-	}
-
-	public boolean isRunning() {
-		return getStatus() == Status.Operating;
-	}
-
-	public String getStandardOutput() {
-		return run.stdout().getAsTextPlain(String.class);
-	}
-
-	public String getStandardError() {
-		return run.stderr().getAsTextPlain(String.class);
-	}
-
-	public String getLog() {
-		return run.log().getAsTextPlain(String.class);
-	}
-
-	public Integer getExitCode() {
-		String code = run.listeners().name("io")
-				.propertiesPropertyName("exitCode")
-				.getAsTextPlain(String.class);
-		if (code == null || code.trim().isEmpty())
-			return null;
-		return Integer.parseInt(code);
-	}
-
-	public String getProperty(Property prop) {
-		return run.listeners().name("io")
-				.propertiesPropertyName(prop.toString())
-				.getAsTextPlain(String.class);
-	}
-
-	public void setGenerateRunBundle(boolean generateRunBundle) {
-		run.generateProvenance().putTextPlain(generateRunBundle, String.class);
-	}
-
-	public byte[] getRunBundle() {
-		return run.runBundle().getAsVndWf4everRobundleZip(byte[].class);
-	}
-
-	public List<InputPort> getInputs() {
-		return run.input().expected().getAsInputDescriptionXml().getInput();
-	}
-
-	public List<OutputPort> getOutputs() {
-		return run.output().getAsOutputDescriptionXml().getOutput();
-	}
-
-	public void setInput(String name, String value) {
-		Value v = new Value();
-		v.setValue(value);
-		InputDescription idesc = new InputDescription();
-		idesc.setValue(v);
-		run.input().inputName(name).putXmlAsInputDescription(idesc);
-	}
-
-	public void setInput(String name, String value, char listSeparator) {
-		Value v = new Value();
-		v.setValue(value);
-		InputDescription idesc = new InputDescription();
-		idesc.setValue(v);
-		idesc.setListDelimiter(new String(new char[] { listSeparator }));
-		run.input().inputName(name).putXmlAsInputDescription(idesc);
-	}
-
-	public byte[] getWorkflow() {
-		return run.workflow().getAsVndTavernaT2flowXml(byte[].class);
-	}
-
-	// TODO Consider better ways to do this
-	public Element getInteractionFeed() {
-		return run.interaction().getAsAtomXml(Element.class);
-	}
-
-	public Element getInteractionEntry(String id) {
-		return run.interaction().id(id).getAsAtomXml(Element.class);
-	}
-
-	public JobUsageRecord getUsageRecord() throws JAXBException {
-		return JobUsageRecord.unmarshal(run.usage().getAsXml(Element.class));
-	}
-
-	public Directory getWorkingDirectory() {
-		return new Directory(this);
-	}
-
-	public String getOwner() {
-		return run.security().owner().getAsTextPlain(String.class);
-	}
-
-	// TODO permissions
-
-	public void grantPasswordCredential(URI contextService, String username,
-			String password) throws ClientException, ServerException {
-		PasswordCredential pc = new PasswordCredential();
-		pc.setServiceURI(contextService.toString());
-		pc.setUsername(username);
-		pc.setPassword(password);
-		checkError(run.security().credentials()
-				.postXmlAsOctetStream(pc, ClientResponse.class));
-	}
-
-	public void grantKeyCredential(URI contextService, java.io.File source,
-			String unlockPassword, String aliasEntry) throws IOException,
-			ClientException, ServerException {
-		KeyPairCredential kpc = new KeyPairCredential();
-		kpc.setServiceURI(contextService.toString());
-		try (InputStream in = new FileInputStream(source)) {
-			byte[] buffer = new byte[(int) source.length()];
-			IOUtils.read(in, buffer);
-			kpc.setCredentialBytes(buffer);
-		}
-		if (source.getName().endsWith(".p12"))
-			kpc.setFileType("PKCS12");
-		else
-			kpc.setFileType("JKS");
-		kpc.setCredentialName(aliasEntry);
-		kpc.setUnlockPassword(unlockPassword);
-		checkError(run.security().credentials()
-				.postXmlAsOctetStream(kpc, ClientResponse.class));
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/Status.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/Status.java b/server-client/src/main/java/uk/org/taverna/server/client/Status.java
deleted file mode 100644
index 9c375ad..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/Status.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package uk.org.taverna.server.client;
-
-/**
- * States of a workflow run. They are {@link #Initialized Initialized},
- * {@link #Operating Operating}, {@link #Stopped Stopped}, and
- * {@link #Finished Finished}. Conceptually, there is also a
- * <tt>Destroyed</tt> state, but the workflow run does not exist (and hence
- * can't have its state queried or set) in that case.
- * 
- * @author Donal Fellows
- */
-public enum Status {
-	/**
-	 * The workflow run has been created, but is not yet running. The run
-	 * will need to be manually moved to {@link #Operating Operating} when
-	 * ready.
-	 */
-	Initialized,
-	/**
-	 * The workflow run is going, reading input, generating output, etc.
-	 * Will eventually either move automatically to {@link #Finished
-	 * Finished} or can be moved manually to {@link #Stopped Stopped} (where
-	 * supported).
-	 */
-	Operating,
-	/**
-	 * The workflow run is paused, and will need to be moved back to
-	 * {@link #Operating Operating} manually.
-	 */
-	Stopped,
-	/**
-	 * The workflow run has ceased; data files will continue to exist until
-	 * the run is destroyed (which may be manual or automatic).
-	 */
-	Finished
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java b/server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
deleted file mode 100644
index 7c0dcdd..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/TavernaServer.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package uk.org.taverna.server.client;
-
-import static java.nio.file.Files.readAllBytes;
-import static org.taverna.server.client.wadl.TavernaServer.createClient;
-import static org.taverna.server.client.wadl.TavernaServer.root;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.taverna.server.client.wadl.TavernaServer.Root;
-
-import uk.org.taverna.server.client.generic.Capability;
-import uk.org.taverna.server.client.generic.TavernaRun;
-import uk.org.taverna.server.client.generic.VersionedElement;
-
-import com.sun.jersey.api.client.Client;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
-
-public class TavernaServer extends Connected {
-	final Root root;
-	private final URI location;
-	private final boolean authenticated;
-
-	TavernaServer(URI serviceRoot) {
-		root = root(createClient(), location = serviceRoot);
-		authenticated = false;
-	}
-
-	TavernaServer(URI serviceRoot, String username, String password) {
-		Client client = createClient();
-		client.addFilter(new HTTPBasicAuthFilter(username, password));
-		authenticated = true;
-		root = root(client, location = serviceRoot);
-	}
-
-	TavernaServer(TavernaServer service, String username, String password) {
-		Client client = createClient();
-		client.addFilter(new HTTPBasicAuthFilter(username, password));
-		authenticated = true;
-		root = root(client, location = service.location);
-		getServerVersionInfo();
-	}
-
-	public TavernaServer upgradeToAuth(String username, String password) {
-		if (authenticated)
-			throw new IllegalStateException("may only upgrade an unauthenticated connection");
-		return new TavernaServer(this, username, password);
-	}
-
-	public List<Capability> getCapabilities() {
-		return root.policy().capabilities().getAsCapabilitiesXml()
-				.getCapability();
-	}
-
-	public int getRunLimit() {
-		return root.policy().runLimit().getAsTextPlain(Integer.class);
-	}
-
-	public int getOperatingLimit() {
-		return root.policy().operatingLimit().getAsTextPlain(Integer.class);
-	}
-
-	public List<String> getPermittedWorkflows() {
-		return root.policy().permittedWorkflows().getAsPermittedWorkflowsXml()
-				.getWorkflow();
-	}
-
-	public List<Run> getExistingRuns() {
-		List<Run> runs = new ArrayList<>();
-		for (TavernaRun run : root.runs().getAsRunListXml().getRun())
-			runs.add(new Run(this, run.getValue()));
-		return runs;
-	}
-
-	public VersionedElement getServerVersionInfo() {
-		return root.getAsServerDescriptionXml();
-	}
-
-	private Run response2run(ClientResponse response) throws ClientException, ServerException {
-		checkError(response);
-		if (response.getClientResponseStatus().getStatusCode() == 201) {
-			String[] path = response.getLocation().getPath().split("/");
-			return new Run(this, path[path.length - 1]);
-		}
-		return null;
-	}
-
-	public Run createWorkflowRun(byte[] t2flowBytes) throws ClientException, ServerException {
-		return response2run(root.runs().postVndTavernaT2flowXmlAsOctetStream(
-				t2flowBytes, ClientResponse.class));
-	}
-
-	public Run createWorkflowRun(File t2flowFile) throws IOException, ClientException, ServerException {
-		return createWorkflowRun(readAllBytes(t2flowFile.toPath()));
-	}
-
-	public Run createWorkflowRun(URI t2flowUri) throws ClientException, ServerException {
-		return response2run(root.runs().postTextUriListAsOctetStream(
-				t2flowUri.toString(), ClientResponse.class));
-	}
-
-
-	public static class ClientException extends Exception {
-		private static final long serialVersionUID = 1L;
-
-		ClientException(String msg, Throwable cause) {
-			super(msg, cause);
-		}
-	}
-	public static class AuthorizationException extends ClientException {
-		private static final long serialVersionUID = 1L;
-
-		AuthorizationException(String msg, Throwable cause) {
-			super(msg, cause);
-		}
-	}
-	static class ServerException extends Exception {
-		private static final long serialVersionUID = 1L;
-
-		ServerException(String msg, Throwable cause) {
-			super(msg, cause);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java b/server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
deleted file mode 100644
index b00b075..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/TavernaServerConnectionFactory.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package uk.org.taverna.server.client;
-
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-
-public class TavernaServerConnectionFactory {
-	private Map<URI, TavernaServer> cache = new HashMap<>();
-
-	public synchronized TavernaServer connectNoAuth(URI uri) {
-		TavernaServer conn = cache.get(uri);
-		if (conn == null)
-			cache.put(uri, conn = new TavernaServer(uri));
-		return conn;
-	}
-
-	public TavernaServer connectAuth(URI uri, String username, String password) {
-		TavernaServer conn = new TavernaServer(uri, username, password);
-		// Force a check of the credentials by getting the server version
-		conn.getServerVersionInfo();
-		return conn;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-client/src/main/java/uk/org/taverna/server/client/package-info.java
----------------------------------------------------------------------
diff --git a/server-client/src/main/java/uk/org/taverna/server/client/package-info.java b/server-client/src/main/java/uk/org/taverna/server/client/package-info.java
deleted file mode 100644
index 59e809d..0000000
--- a/server-client/src/main/java/uk/org/taverna/server/client/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * Implementation of a basic client for Taverna Server.
- * @author Donal Fellows
- */
-package uk.org.taverna.server.client;
\ No newline at end of file


[02/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd b/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
new file mode 100644
index 0000000..a485e30
--- /dev/null
+++ b/taverna-server-webapp/src/misc/xsd/persistence_1_0.xsd
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- persistence.xml schema -->
+<xsd:schema targetNamespace="http://java.sun.com/xml/ns/persistence" 
+  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+  xmlns:persistence="http://java.sun.com/xml/ns/persistence"
+  elementFormDefault="qualified" 
+  attributeFormDefault="unqualified" 
+  version="1.0">
+
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)persistence_1_0.xsd  1.0  Feb 9 2006
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+      Copyright 2005-2007 Sun Microsystems, Inc. All rights reserved.
+
+      The contents of this file are subject to the terms of either the
+      GNU General Public License Version 2 only ("GPL") or the Common
+      Development and Distribution License("CDDL") (collectively, the
+      "License").  You may not use this file except in compliance with
+      the License. You can obtain a copy of the License at
+      https://glassfish.dev.java.net/public/CDDL+GPL.html or
+      glassfish/bootstrap/legal/LICENSE.txt.  See the License for the
+      specific language governing permissions and limitations under the
+      License.
+
+      When distributing the software, include this License Header
+      Notice in each file and include the License file at
+      glassfish/bootstrap/legal/LICENSE.txt.  Sun designates this
+      particular file as subject to the "Classpath" exception as
+      provided by Sun in the GPL Version 2 section of the License file
+      that accompanied this code.  If applicable, add the following
+      below the License Header, with the fields enclosed by brackets []
+      replaced by your own identifying information:
+      "Portions Copyrighted [year] [name of copyright owner]"
+
+      Contributor(s):
+
+      If you wish your version of this file to be governed by only the
+      CDDL or only the GPL Version 2, indicate your decision by adding
+      "[Contributor] elects to include this software in this
+      distribution under the [CDDL or GPL Version 2] license."  If you
+      don't indicate a single choice of license, a recipient has the
+      option to distribute your version of this file under either the
+      CDDL, the GPL Version 2 or to extend the choice of license to its
+      licensees as provided above.  However, if you add GPL Version 2
+      code and therefore, elected the GPL Version 2 license, then the
+      option applies only if the new code is made subject to such
+      option by the copyright holder.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+   <xsd:annotation>
+     <xsd:documentation><![CDATA[
+
+     This is the XML Schema for the persistence configuration file.
+     The file must be named "META-INF/persistence.xml" in the 
+     persistence archive.
+     Persistence configuration files must indicate
+     the persistence schema by using the persistence namespace:
+
+     http://java.sun.com/xml/ns/persistence
+
+     and indicate the version of the schema by
+     using the version element as shown below:
+
+      <persistence xmlns="http://java.sun.com/xml/ns/persistence"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
+          http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+        version="1.0">
+          ...
+      </persistence>
+
+    ]]></xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:simpleType name="versionType">
+    <xsd:restriction base="xsd:token">
+      <xsd:pattern value="[0-9]+(\.[0-9]+)*"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <!-- **************************************************** -->
+
+  <xsd:element name="persistence">
+    <xsd:complexType>
+      <xsd:sequence>
+
+        <!-- **************************************************** -->
+
+        <xsd:element name="persistence-unit" 
+                     minOccurs="0" maxOccurs="unbounded">
+          <xsd:complexType>
+            <xsd:annotation>
+              <xsd:documentation>
+
+                Configuration of a persistence unit.
+
+              </xsd:documentation>
+            </xsd:annotation>
+            <xsd:sequence>
+
+            <!-- **************************************************** -->
+
+              <xsd:element name="description" type="xsd:string" 
+                           minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    Textual description of this persistence unit.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="provider" type="xsd:string" 
+                           minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    Provider class that supplies EntityManagers for this 
+                    persistence unit.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="jta-data-source" type="xsd:string" 
+                           minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    The container-specific name of the JTA datasource to use.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="non-jta-data-source" type="xsd:string" 
+                           minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    The container-specific name of a non-JTA datasource to use.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="mapping-file" type="xsd:string" 
+                           minOccurs="0" maxOccurs="unbounded">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    File containing mapping information. Loaded as a resource 
+                    by the persistence provider.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="jar-file" type="xsd:string" 
+                           minOccurs="0" maxOccurs="unbounded">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    Jar file that should be scanned for entities. 
+                    Not applicable to Java SE persistence units.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="class" type="xsd:string" 
+                           minOccurs="0" maxOccurs="unbounded">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    Class to scan for annotations.  It should be annotated 
+                    with either @Entity, @Embeddable or @MappedSuperclass.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="exclude-unlisted-classes" type="xsd:boolean" 
+                           default="false" minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    When set to true then only listed classes and jars will 
+                    be scanned for persistent classes, otherwise the enclosing 
+                    jar or directory will also be scanned. Not applicable to 
+                    Java SE persistence units.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+              </xsd:element>
+
+              <!-- **************************************************** -->
+
+              <xsd:element name="properties" minOccurs="0">
+                <xsd:annotation>
+                  <xsd:documentation>
+
+                    A list of vendor-specific properties.
+
+                  </xsd:documentation>
+                </xsd:annotation>
+                <xsd:complexType>
+                  <xsd:sequence>
+                    <xsd:element name="property" 
+                                 minOccurs="0" maxOccurs="unbounded">
+                      <xsd:annotation>
+                        <xsd:documentation>
+                          A name-value pair.
+                        </xsd:documentation>
+                      </xsd:annotation>
+                      <xsd:complexType>
+                        <xsd:attribute name="name" type="xsd:string" 
+                                       use="required"/>
+                        <xsd:attribute name="value" type="xsd:string" 
+                                       use="required"/>
+                      </xsd:complexType>
+                    </xsd:element>
+                  </xsd:sequence>
+                </xsd:complexType>
+              </xsd:element>
+
+            </xsd:sequence>
+
+            <!-- **************************************************** -->
+
+            <xsd:attribute name="name" type="xsd:string" use="required">
+              <xsd:annotation>
+                <xsd:documentation>
+
+                  Name used in code to reference this persistence unit.
+
+                </xsd:documentation>
+              </xsd:annotation>
+            </xsd:attribute>
+
+            <!-- **************************************************** -->
+
+            <xsd:attribute name="transaction-type" 
+                           type="persistence:persistence-unit-transaction-type">
+              <xsd:annotation>
+                <xsd:documentation>
+
+                  Type of transactions used by EntityManagers from this 
+                  persistence unit.
+
+                </xsd:documentation>
+              </xsd:annotation>
+            </xsd:attribute>
+
+          </xsd:complexType>
+        </xsd:element>
+      </xsd:sequence>
+      <xsd:attribute name="version" type="persistence:versionType" 
+                     fixed="1.0" use="required"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <!-- **************************************************** -->
+
+  <xsd:simpleType name="persistence-unit-transaction-type">
+    <xsd:annotation>
+      <xsd:documentation>
+
+        public enum TransactionType { JTA, RESOURCE_LOCAL };
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base="xsd:token">
+      <xsd:enumeration value="JTA"/>
+      <xsd:enumeration value="RESOURCE_LOCAL"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+</xsd:schema>
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
new file mode 100644
index 0000000..79c026b
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/JaxbSanityTest.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Arrays;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.transform.Result;
+import javax.xml.transform.stream.StreamResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.master.admin.Admin;
+import org.taverna.server.master.common.Credential.KeyPair;
+import org.taverna.server.master.common.Credential.Password;
+import org.taverna.server.master.common.Capability;
+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.Uri;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.rest.DirectoryContents;
+import org.taverna.server.master.rest.ListenerDefinition;
+import org.taverna.server.master.rest.MakeOrUpdateDirEntry;
+import org.taverna.server.master.rest.TavernaServerInputREST.InDesc;
+import org.taverna.server.master.rest.TavernaServerInputREST.InputsDescriptor;
+import org.taverna.server.master.rest.TavernaServerListenersREST.ListenerDescription;
+import org.taverna.server.master.rest.TavernaServerListenersREST.Listeners;
+import org.taverna.server.master.rest.TavernaServerListenersREST.Properties;
+import org.taverna.server.master.rest.TavernaServerListenersREST.PropertyDescription;
+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.CapabilityList;
+import org.taverna.server.master.rest.TavernaServerREST.PolicyView.PolicyDescription;
+import org.taverna.server.master.rest.TavernaServerREST.RunList;
+import org.taverna.server.master.rest.TavernaServerREST.ServerDescription;
+import org.taverna.server.master.rest.TavernaServerRunREST.RunDescription;
+import org.taverna.server.master.rest.TavernaServerSecurityREST;
+import org.taverna.server.master.rest.TavernaServerSecurityREST.CredentialHolder;
+import org.taverna.server.master.soap.DirEntry;
+import org.taverna.server.master.soap.FileContents;
+import org.taverna.server.master.soap.PermissionList;
+
+/**
+ * This test file ensures that the JAXB bindings will work once deployed instead
+ * of mysteriously failing in service.
+ * 
+ * @author Donal Fellows
+ */
+public class JaxbSanityTest {
+	SchemaOutputResolver sink;
+	StringWriter schema;
+
+	String schema() {
+		return schema.toString();
+	}
+
+	@Before
+	public void init() {
+		schema = new StringWriter();
+		sink = new SchemaOutputResolver() {
+			@Override
+			public Result createOutput(String namespaceUri,
+					String suggestedFileName) throws IOException {
+				StreamResult sr = new StreamResult(schema);
+				sr.setSystemId("/dev/null");
+				return sr;
+			}
+		};
+		assertEquals("", schema());
+	}
+
+	private boolean printSchema = false;
+
+	private void testJAXB(Class<?>... classes) throws Exception {
+		JAXBContext.newInstance(classes).generateSchema(sink);
+		if (printSchema)
+			System.out.println(schema());
+		assertTrue(schema().length() > 0);
+	}
+
+	@Test
+	public void testJAXBForDirEntryReference() throws Exception {
+		JAXBContext.newInstance(DirEntryReference.class).generateSchema(sink);
+		assertTrue(schema().length() > 0);
+	}
+
+	@Test
+	public void testJAXBForInputDescription() throws Exception {
+		testJAXB(InputDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunReference() throws Exception {
+		testJAXB(RunReference.class);
+	}
+
+	@Test
+	public void testJAXBForWorkflow() throws Exception {
+		testJAXB(Workflow.class);
+	}
+
+	@Test
+	public void testJAXBForStatus() throws Exception {
+		testJAXB(Status.class);
+	}
+
+	@Test
+	public void testJAXBForUri() throws Exception {
+		testJAXB(Uri.class);
+	}
+
+	@Test
+	public void testJAXBForDirectoryContents() throws Exception {
+		testJAXB(DirectoryContents.class);
+	}
+
+	@Test
+	public void testJAXBForListenerDefinition() throws Exception {
+		testJAXB(ListenerDefinition.class);
+	}
+
+	@Test
+	public void testJAXBForMakeOrUpdateDirEntry() throws Exception {
+		testJAXB(MakeOrUpdateDirEntry.class);
+	}
+
+	@Test
+	public void testJAXBForInDesc() throws Exception {
+		testJAXB(InDesc.class);
+	}
+
+	@Test
+	public void testJAXBForInputsDescriptor() throws Exception {
+		testJAXB(InputsDescriptor.class);
+	}
+
+	@Test
+	public void testJAXBForListenerDescription() throws Exception {
+		testJAXB(ListenerDescription.class);
+	}
+
+	@Test
+	public void testJAXBForListeners() throws Exception {
+		testJAXB(Listeners.class);
+	}
+
+	@Test
+	public void testJAXBForProperties() throws Exception {
+		testJAXB(Properties.class);
+	}
+
+	@Test
+	public void testJAXBForPropertyDescription() throws Exception {
+		testJAXB(PropertyDescription.class);
+	}
+
+	@Test
+	public void testJAXBForPermittedListeners() throws Exception {
+		testJAXB(PermittedListeners.class);
+	}
+
+	@Test
+	public void testJAXBForPermittedWorkflows() throws Exception {
+		testJAXB(PermittedWorkflows.class);
+	}
+
+	@Test
+	public void testJAXBForEnabledNotifiers() throws Exception {
+		testJAXB(EnabledNotificationFabrics.class);
+	}
+
+	@Test
+	public void testJAXBForServerDescription() throws Exception {
+		testJAXB(ServerDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunDescription() throws Exception {
+		testJAXB(RunDescription.class);
+	}
+
+	@Test
+	public void testJAXBForRunList() throws Exception {
+		testJAXB(RunList.class);
+	}
+
+	@Test
+	public void testJAXBForPolicyDescription() throws Exception {
+		testJAXB(PolicyDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityCredential() throws Exception {
+		testJAXB(CredentialHolder.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityCredentialList() throws Exception {
+		testJAXB(TavernaServerSecurityREST.CredentialList.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityTrust() throws Exception {
+		testJAXB(Trust.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityTrustList() throws Exception {
+		testJAXB(TavernaServerSecurityREST.TrustList.class);
+	}
+
+	@Test
+	public void testJAXBForPermission() throws Exception {
+		testJAXB(Permission.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityPermissionDescription() throws Exception {
+		testJAXB(TavernaServerSecurityREST.PermissionDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityPermissionsDescription() throws Exception {
+		testJAXB(TavernaServerSecurityREST.PermissionsDescription.class);
+	}
+
+	@Test
+	public void testJAXBForSecurityDescriptor() throws Exception {
+		testJAXB(TavernaServerSecurityREST.Descriptor.class);
+	}
+
+	@Test
+	public void testJAXBForProfileList() throws Exception {
+		testJAXB(ProfileList.class);
+	}
+
+	@Test
+	public void testJAXBForDirEntry() throws Exception {
+		testJAXB(DirEntry.class);
+	}
+
+	@Test
+	public void testJAXBForCapability() throws Exception {
+		testJAXB(Capability.class);
+	}
+
+	@Test
+	public void testJAXBForCapabilityList() throws Exception {
+		testJAXB(CapabilityList.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingREST() throws Exception {
+		testJAXB(DirEntryReference.class, InputDescription.class,
+				RunReference.class, Workflow.class, Status.class,
+				DirectoryContents.class, InDesc.class,
+				ListenerDefinition.class, MakeOrUpdateDirEntry.class,
+				InputsDescriptor.class, ListenerDescription.class,
+				Listeners.class, Properties.class, PropertyDescription.class,
+				PermittedListeners.class, PermittedWorkflows.class,
+				EnabledNotificationFabrics.class, ServerDescription.class,
+				RunDescription.class, Uri.class, RunList.class,
+				PolicyDescription.class, CredentialHolder.class, Trust.class,
+				TavernaServerSecurityREST.CredentialList.class,
+				TavernaServerSecurityREST.TrustList.class, Permission.class,
+				TavernaServerSecurityREST.Descriptor.class,
+				TavernaServerSecurityREST.PermissionDescription.class,
+				TavernaServerSecurityREST.PermissionsDescription.class,
+				ProfileList.class, Capability.class, CapabilityList.class);
+	}
+
+	@Test
+	public void testJAXBForEverythingSOAP() throws Exception {
+		testJAXB(DirEntry.class, FileContents.class, InputDescription.class,
+				Permission.class, PermissionList.class,
+				PermissionList.SinglePermissionMapping.class,
+				RunReference.class, Status.class, Trust.class, Uri.class,
+				ProfileList.class, Workflow.class, Capability.class);
+	}
+
+	@Test
+	public void testUserPassSerializeDeserialize() throws Exception {
+		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
+
+		Password password = new Password();
+		password.username = "foo";
+		password.password = "bar";
+
+		// Serialize
+		StringWriter sw = new StringWriter();
+		CredentialHolder credIn = new CredentialHolder(password);
+		c.createMarshaller().marshal(credIn, sw);
+
+		// Deserialize
+		StringReader sr = new StringReader(sw.toString());
+		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
+
+		// Test value-equivalence
+		assertEquals(credIn.getClass(), credOutObj.getClass());
+		CredentialHolder credOut = (CredentialHolder) credOutObj;
+		assertEquals(credIn.credential.getClass(),
+				credOut.credential.getClass());
+		assertEquals(credIn.getUserpass().username,
+				credOut.getUserpass().username);
+		assertEquals(credIn.getUserpass().password,
+				credOut.getUserpass().password);
+	}
+
+	@Test
+	public void testKeypairSerializeDeserialize() throws Exception {
+		JAXBContext c = JAXBContext.newInstance(CredentialHolder.class);
+
+		KeyPair keypair = new KeyPair();
+		keypair.credentialName = "foo";
+		keypair.credentialBytes = new byte[] { 1, 2, 3 };
+
+		// Serialize
+		StringWriter sw = new StringWriter();
+		CredentialHolder credIn = new CredentialHolder(keypair);
+		c.createMarshaller().marshal(credIn, sw);
+
+		// Deserialize
+		StringReader sr = new StringReader(sw.toString());
+		Object credOutObj = c.createUnmarshaller().unmarshal(sr);
+
+		// Test value-equivalence
+		assertEquals(credIn.getClass(), credOutObj.getClass());
+		CredentialHolder credOut = (CredentialHolder) credOutObj;
+		assertEquals(credIn.credential.getClass(),
+				credOut.credential.getClass());
+		assertEquals(credIn.getKeypair().credentialName,
+				credOut.getKeypair().credentialName);
+		assertTrue(Arrays.equals(credIn.getKeypair().credentialBytes,
+				credOut.getKeypair().credentialBytes));
+	}
+
+	@Test
+	public void testJAXBforAdmininstration() throws Exception {
+		testJAXB(Admin.AdminDescription.class);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
new file mode 100644
index 0000000..9665cf0
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/TavernaServerImplTest.java
@@ -0,0 +1,246 @@
+package org.taverna.server.master;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.common.RunReference;
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+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.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.mocks.ExampleRun;
+import org.taverna.server.master.mocks.MockPolicy;
+import org.taverna.server.master.mocks.SimpleListenerFactory;
+import org.taverna.server.master.mocks.SimpleNonpersistentRunStore;
+
+public class TavernaServerImplTest {
+	private TavernaServer server;
+	private MockPolicy policy;
+	private SimpleNonpersistentRunStore store;
+	@java.lang.SuppressWarnings("unused")
+	private ExampleRun.Builder runFactory;
+	private SimpleListenerFactory lFactory;
+	private TavernaServerSupport support;
+
+	private String lrunname;
+	private String lrunconf;
+
+	Listener makeListener(TavernaRun run, final String config) {
+		lrunname = run.toString();
+		lrunconf = config;
+		return new Listener() {
+			@Override
+			public String getConfiguration() {
+				return config;
+			}
+
+			@Override
+			public String getName() {
+				return "bar";
+			}
+
+			@Override
+			public String getProperty(String propName)
+					throws NoListenerException {
+				throw new NoListenerException();
+			}
+
+			@Override
+			public String getType() {
+				return "foo";
+			}
+
+			@Override
+			public String[] listProperties() {
+				return new String[0];
+			}
+
+			@Override
+			public void setProperty(String propName, String value)
+					throws NoListenerException, BadPropertyValueException {
+				throw new NoListenerException();
+			}
+		};
+	}
+
+	@Before
+	public void wireup() throws Exception {
+		// Wire everything up; ought to be done with Spring, but this works...
+		server = new TavernaServer() {
+			@Override
+			protected RunREST makeRunInterface() {
+				return new RunREST() {
+					@Override
+					protected ListenersREST makeListenersInterface() {
+						return new ListenersREST() {
+							@Override
+							protected SingleListenerREST makeListenerInterface() {
+								return new SingleListenerREST() {
+									@Override
+									protected ListenerPropertyREST makePropertyInterface() {
+										return new ListenerPropertyREST() {
+										};
+									}
+								};
+							}
+						};
+					}
+
+					@Override
+					protected RunSecurityREST makeSecurityInterface() {
+						return new RunSecurityREST() {
+						};
+					}
+
+					@Override
+					protected DirectoryREST makeDirectoryInterface() {
+						return new DirectoryREST() {
+						};
+					}
+
+					@Override
+					protected InputREST makeInputInterface() {
+						return new InputREST() {
+						};
+					}
+
+					@Override
+					protected InteractionFeed makeInteractionFeed() {
+						return null; // TODO...
+					}
+				};
+			}
+
+			@Override
+			public PolicyView getPolicyDescription() {
+				return new PolicyREST();
+			}
+		};
+		support = new TavernaServerSupport();
+		server.setSupport(support);
+		support.setWebapp(server);
+		support.setLogGetPrincipalFailures(false);
+		support.setStateModel(new ManagementModel() {
+			@Override
+			public boolean getAllowNewWorkflowRuns() {
+				return true;
+			}
+
+			@Override
+			public boolean getLogIncomingWorkflows() {
+				return false;
+			}
+
+			@Override
+			public boolean getLogOutgoingExceptions() {
+				return false;
+			}
+
+			@Override
+			public void setAllowNewWorkflowRuns(boolean allowNewWorkflowRuns) {
+			}
+
+			@Override
+			public void setLogIncomingWorkflows(boolean logIncomingWorkflows) {
+			}
+
+			@Override
+			public void setLogOutgoingExceptions(boolean logOutgoingExceptions) {
+			}
+
+			@Override
+			public String getUsageRecordLogFile() {
+				return null;
+			}
+
+			@Override
+			public void setUsageRecordLogFile(String usageRecordLogFile) {
+			}
+		});
+		server.setPolicy(policy = new MockPolicy());
+		support.setPolicy(policy);
+		server.setRunStore(store = new SimpleNonpersistentRunStore());
+		support.setRunStore(store);
+		store.setPolicy(policy);
+		support.setRunFactory(runFactory = new ExampleRun.Builder(1));
+		support.setListenerFactory(lFactory = new SimpleListenerFactory());
+		lFactory.setBuilders(singletonMap(
+				"foo",
+				(SimpleListenerFactory.Builder) new SimpleListenerFactory.Builder() {
+					@Override
+					public Listener build(TavernaRun run, String configuration)
+							throws NoListenerException {
+						return makeListener(run, configuration);
+					}
+				}));
+	}
+
+	@Test
+	public void defaults1() {
+		assertNotNull(server);
+	}
+
+	@Test
+	public void defaults2() {
+		assertEquals(10, server.getServerMaxRuns());
+	}
+
+	@Test
+	public void defaults3() {
+		assertEquals(1, server.getServerListeners().length);
+	}
+
+	@Test
+	public void defaults4() {
+		assertNotNull(support.getPrincipal());
+	}
+
+	@Test
+	public void serverAsksPolicyForMaxRuns() {
+		int oldmax = policy.maxruns;
+		try {
+			policy.maxruns = 1;
+			assertEquals(1, server.getServerMaxRuns());
+		} finally {
+			policy.maxruns = oldmax;
+		}
+	}
+
+	@Test
+	public void makeAndKillARun() throws NoUpdateException, UnknownRunException {
+		RunReference rr = server.submitWorkflow(null);
+		assertNotNull(rr);
+		assertNotNull(rr.name);
+		server.destroyRun(rr.name);
+	}
+
+	@Test
+	public void makeListenKillRun() throws Exception {
+		RunReference run = server.submitWorkflow(null);
+		try {
+			lrunname = lrunconf = null;
+			assertEquals(asList("foo"), asList(server.getServerListeners()));
+			String l = server.addRunListener(run.name, "foo", "foobar");
+			assertEquals("bar", l);
+			assertEquals("foobar", lrunconf);
+			assertEquals(lrunname, support.getRun(run.name).toString());
+			assertEquals(asList("default", "bar"),
+					asList(server.getRunListeners(run.name)));
+			assertEquals(0,
+					server.getRunListenerProperties(run.name, "bar").length);
+		} finally {
+			try {
+				server.destroyRun(run.name);
+			} catch (Exception e) {
+				// Ignore
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
new file mode 100644
index 0000000..0450317
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/WorkflowSerializationTest.java
@@ -0,0 +1,68 @@
+package org.taverna.server.master;
+
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_NS;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW_ROOTNAME;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.taverna.server.master.common.Workflow;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class WorkflowSerializationTest {
+	@Test
+	public void testWorkflowSerialization()
+			throws ParserConfigurationException, IOException,
+			ClassNotFoundException {
+		DocumentBuilder db = DocumentBuilderFactory.newInstance()
+				.newDocumentBuilder();
+		Document doc = db.getDOMImplementation().createDocument(null, null,
+				null);
+		Element workflow = doc.createElementNS(T2FLOW_NS, T2FLOW_ROOTNAME);
+		Element foo = doc.createElementNS("urn:foo:bar", "pqr:foo");
+		foo.setTextContent("bar");
+		foo.setAttribute("xyz", "abc");
+		workflow.appendChild(foo);
+		Workflow w = new Workflow(workflow);
+
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+			oos.writeObject(w);
+		}
+
+		Object o;
+		try (ObjectInputStream ois = new ObjectInputStream(
+				new ByteArrayInputStream(baos.toByteArray()))) {
+			o = ois.readObject();
+		}
+
+		Assert.assertNotNull(o);
+		Assert.assertEquals(w.getClass(), o.getClass());
+		Workflow w2 = (Workflow) o;
+		Assert.assertNotNull(w2.getT2flowWorkflow());
+		Element e = w2.getT2flowWorkflow();
+		Assert.assertEquals(T2FLOW_ROOTNAME, e.getLocalName());
+		Assert.assertEquals(T2FLOW_NS, e.getNamespaceURI());
+		e = (Element) e.getFirstChild();
+		Assert.assertEquals("foo", e.getLocalName());
+		Assert.assertEquals("pqr", e.getPrefix());
+		Assert.assertEquals("urn:foo:bar", e.getNamespaceURI());
+		Assert.assertEquals("bar", e.getTextContent());
+		Assert.assertEquals(1, e.getChildNodes().getLength());
+		// WARNING: These are dependent on how namespaces are encoded!
+		Assert.assertEquals(2, e.getAttributes().getLength());
+		Assert.assertEquals("xyz", ((Attr) e.getAttributes().item(1)).getLocalName());
+		Assert.assertEquals("abc", e.getAttribute("xyz"));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
new file mode 100644
index 0000000..a2a0791
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/ExampleRun.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.mocks;
+
+import static java.util.Calendar.MINUTE;
+import static java.util.Collections.unmodifiableList;
+import static java.util.UUID.randomUUID;
+import static org.taverna.server.master.common.Status.Initialized;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.xml.ws.handler.MessageContext;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.taverna.server.master.common.Credential;
+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.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+import org.taverna.server.master.factories.RunFactory;
+import org.taverna.server.master.interfaces.Directory;
+import org.taverna.server.master.interfaces.Input;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.SecurityContextFactory;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+@SuppressWarnings("serial")
+public class ExampleRun implements TavernaRun, TavernaSecurityContext {
+	String id;
+	List<Listener> listeners;
+	Workflow workflow;
+	Status status;
+	Date expiry;
+	UsernamePrincipal owner;
+	String inputBaclava;
+	String outputBaclava;
+	java.io.File realRoot;
+	List<Input> inputs;
+	String name;
+
+	public ExampleRun(UsernamePrincipal creator, Workflow workflow, Date expiry) {
+		this.id = randomUUID().toString();
+		this.listeners = new ArrayList<>();
+		this.status = Initialized;
+		this.owner = creator;
+		this.workflow = workflow;
+		this.expiry = expiry;
+		this.inputs = new ArrayList<>();
+		listeners.add(new DefaultListener());
+	}
+
+	@Override
+	public void addListener(Listener l) {
+		listeners.add(l);
+	}
+
+	@Override
+	public void destroy() {
+		// This does nothing...
+	}
+
+	@Override
+	public Date getExpiry() {
+		return expiry;
+	}
+
+	@Override
+	public List<Listener> getListeners() {
+		return listeners;
+	}
+
+	@Override
+	public TavernaSecurityContext getSecurityContext() {
+		return this;
+	}
+
+	@Override
+	public Status getStatus() {
+		return status;
+	}
+
+	@Override
+	public Workflow getWorkflow() {
+		return workflow;
+	}
+
+	@Override
+	public Directory getWorkingDirectory() {
+		// LATER: Implement this!
+		throw new UnsupportedOperationException("not yet implemented");
+	}
+
+	@Override
+	public void setExpiry(Date d) {
+		if (d.after(new Date()))
+			this.expiry = d;
+	}
+
+	@Override
+	public String setStatus(Status s) {
+		this.status = s;
+		return null;
+	}
+
+	@Override
+	public UsernamePrincipal getOwner() {
+		return owner;
+	}
+
+	public static class Builder implements RunFactory {
+		private int lifetime;
+
+		public Builder(int initialLifetimeMinutes) {
+			this.lifetime = initialLifetimeMinutes;
+		}
+
+		@Override
+		public TavernaRun create(UsernamePrincipal creator, Workflow workflow) {
+			Calendar c = GregorianCalendar.getInstance();
+			c.add(MINUTE, lifetime);
+			return new ExampleRun(creator, workflow, c.getTime());
+		}
+
+		@Override
+		public boolean isAllowingRunsToStart() {
+			return true;
+		}
+	}
+
+	static final String[] emptyArray = new String[0];
+
+	class DefaultListener implements Listener {
+		@Override
+		public String getConfiguration() {
+			return "";
+		}
+
+		@Override
+		public String getName() {
+			return "default";
+		}
+
+		@Override
+		public String getType() {
+			return "default";
+		}
+
+		@Override
+		public String[] listProperties() {
+			return emptyArray;
+		}
+
+		@Override
+		public String getProperty(String propName) throws NoListenerException {
+			throw new NoListenerException("no such property");
+		}
+
+		@Override
+		public void setProperty(String propName, String value)
+				throws NoListenerException {
+			throw new NoListenerException("no such property");
+		}
+	}
+
+	@Override
+	public String getInputBaclavaFile() {
+		return inputBaclava;
+	}
+
+	@Override
+	public List<Input> getInputs() {
+		return unmodifiableList(inputs);
+	}
+
+	@Override
+	public String getOutputBaclavaFile() {
+		return outputBaclava;
+	}
+
+	class ExampleInput implements Input {
+		public String name;
+		public String file;
+		public String value;
+		public String delim;
+
+		public ExampleInput(String name) {
+			this.name = name;
+		}
+
+		@Override
+		public String getFile() {
+			return file;
+		}
+
+		@Override
+		public String getName() {
+			return name;
+		}
+
+		@Override
+		public String getValue() {
+			return value;
+		}
+
+		@Override
+		public void setFile(String file) throws FilesystemAccessException,
+				BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			checkBadFilename(file);
+			this.file = file;
+			this.value = null;
+			inputBaclava = null;
+		}
+
+		@Override
+		public void setValue(String value) throws BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			this.value = value;
+			this.file = null;
+			inputBaclava = null;
+		}
+
+		void reset() {
+			this.file = null;
+			this.value = null;
+		}
+
+		@Override
+		public String getDelimiter() {
+			return delim;
+		}
+
+		@Override
+		public void setDelimiter(String delimiter)
+				throws BadStateChangeException {
+			if (status != Status.Initialized)
+				throw new BadStateChangeException();
+			if (delimiter == null)
+				delim = null;
+			else
+				delim = delimiter.substring(0, 1);
+		}
+	}
+
+	@Override
+	public Input makeInput(String name) throws BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		Input i = new ExampleInput(name);
+		inputs.add(i);
+		return i;
+	}
+
+	static void checkBadFilename(String filename)
+			throws FilesystemAccessException {
+		if (filename.startsWith("/"))
+			throw new FilesystemAccessException("filename may not be absolute");
+		if (Arrays.asList(filename.split("/")).contains(".."))
+			throw new FilesystemAccessException(
+					"filename may not refer to parent");
+	}
+
+	@Override
+	public void setInputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		checkBadFilename(filename);
+		inputBaclava = filename;
+		for (Input i : inputs)
+			((ExampleInput) i).reset();
+	}
+
+	@Override
+	public void setOutputBaclavaFile(String filename)
+			throws FilesystemAccessException, BadStateChangeException {
+		if (status != Status.Initialized)
+			throw new BadStateChangeException();
+		if (filename != null)
+			checkBadFilename(filename);
+		outputBaclava = filename;
+	}
+
+	private Date created = new Date();
+	@Override
+	public Date getCreationTimestamp() {
+		return created;
+	}
+
+	@Override
+	public Date getFinishTimestamp() {
+		return null;
+	}
+
+	@Override
+	public Date getStartTimestamp() {
+		return null;
+	}
+
+	@Override
+	public Credential[] getCredentials() {
+		return new Credential[0];
+	}
+
+	@Override
+	public void addCredential(Credential toAdd) {
+	}
+
+	@Override
+	public void deleteCredential(Credential toDelete) {
+	}
+
+	@Override
+	public Trust[] getTrusted() {
+		return new Trust[0];
+	}
+
+	@Override
+	public void addTrusted(Trust toAdd) {
+	}
+
+	@Override
+	public void deleteTrusted(Trust toDelete) {
+	}
+
+	@Override
+	public void validateCredential(Credential c)
+			throws InvalidCredentialException {
+	}
+
+	@Override
+	public void validateTrusted(Trust t) throws InvalidCredentialException {
+	}
+
+	@Override
+	public void initializeSecurityFromSOAPContext(MessageContext context) {
+		// Do nothing
+	}
+
+	@Override
+	public void initializeSecurityFromRESTContext(HttpHeaders headers) {
+		// Do nothing
+	}
+
+	@Override
+	public void conveySecurity() throws GeneralSecurityException, IOException {
+		// Do nothing
+	}
+
+	@Override
+	public SecurityContextFactory getFactory() {
+		return null;
+	}
+
+	private Set<String> destroyers = new HashSet<String>();
+	private Set<String> updaters = new HashSet<String>();
+	private Set<String> readers = new HashSet<String>();
+	@Override
+	public Set<String> getPermittedDestroyers() {
+		return destroyers;
+	}
+
+	@Override
+	public void setPermittedDestroyers(Set<String> destroyers) {
+		this.destroyers = destroyers;
+		updaters.addAll(destroyers);
+		readers.addAll(destroyers);
+	}
+
+	@Override
+	public Set<String> getPermittedUpdaters() {
+		return updaters;
+	}
+
+	@Override
+	public void setPermittedUpdaters(Set<String> updaters) {
+		this.updaters = updaters;
+		this.updaters.addAll(destroyers);
+		readers.addAll(updaters);
+	}
+
+	@Override
+	public Set<String> getPermittedReaders() {
+		return readers;
+	}
+
+	@Override
+	public void setPermittedReaders(Set<String> readers) {
+		this.readers = readers;
+		this.readers.addAll(destroyers);
+		this.readers.addAll(updaters);
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public void initializeSecurityFromContext(SecurityContext securityContext)
+			throws Exception {
+		// Do nothing
+	}
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public void setName(String name) {
+		this.name = (name.length() > 5 ? name.substring(0, 5) : name);
+	}
+
+	@Override
+	public void ping() throws UnknownRunException {
+		// Do nothing
+	}
+
+	@Override
+	public boolean getGenerateProvenance() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	@Override
+	public void setGenerateProvenance(boolean generateProvenance) {
+		// TODO Auto-generated method stub
+		
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
new file mode 100644
index 0000000..81dd08c
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/MockPolicy.java
@@ -0,0 +1,59 @@
+package org.taverna.server.master.mocks;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+public class MockPolicy extends SimpleServerPolicy {
+	public MockPolicy() {
+		super();
+		super.setCleanerInterval(30);
+	}
+
+	public int maxruns = 10;
+	Integer usermaxruns;
+	Set<TavernaRun> denyaccess = new HashSet<>();
+	boolean exnOnUpdate, exnOnCreate, exnOnDelete;
+
+	@Override
+	public int getMaxRuns() {
+		return maxruns;
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal user) {
+		return usermaxruns;
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
+		return !denyaccess.contains(run);
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException {
+		if (this.exnOnCreate)
+			throw new NoCreateException();
+	}
+
+	@Override
+	public void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException {
+		if (this.exnOnDelete)
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException {
+		if (this.exnOnUpdate)
+			throw new NoUpdateException();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
new file mode 100644
index 0000000..d864214
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleListenerFactory.java
@@ -0,0 +1,64 @@
+package org.taverna.server.master.mocks;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+import org.taverna.server.master.factories.ListenerFactory;
+import org.taverna.server.master.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+
+/**
+ * A factory for event listener. The factory is configured using Spring.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleListenerFactory implements ListenerFactory {
+	private Map<String, Builder> builders = new HashMap<>();
+
+	public void setBuilders(Map<String, Builder> builders) {
+		this.builders = builders;
+	}
+
+	@Override
+	public List<String> getSupportedListenerTypes() {
+		return new ArrayList<>(builders.keySet());
+	}
+
+	@Override
+	public Listener makeListener(TavernaRun run, String listenerType,
+			String configuration) throws NoListenerException {
+		Builder b = builders.get(listenerType);
+		if (b == null)
+			throw new NoListenerException("no such listener type");
+		Listener l = b.build(run, configuration);
+		run.addListener(l);
+		return l;
+	}
+
+	/**
+	 * How to actually construct a listener.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public interface Builder {
+		/**
+		 * Make an event listener attached to a run.
+		 * 
+		 * @param run
+		 *            The run to attach to.
+		 * @param configuration
+		 *            A user-specified configuration document. The constructed
+		 *            listener <i>should</i> process this configuration document
+		 *            and be able to return it to the user when requested.
+		 * @return The listener object.
+		 * @throws NoListenerException
+		 *             If the listener construction failed or the
+		 *             <b>configuration</b> document was bad in some way.
+		 */
+		public Listener build(TavernaRun run, String configuration)
+				throws NoListenerException;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
new file mode 100644
index 0000000..a3751e4
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleNonpersistentRunStore.java
@@ -0,0 +1,151 @@
+package org.taverna.server.master.mocks;
+
+import java.lang.ref.WeakReference;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.UnknownRunException;
+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.utils.UsernamePrincipal;
+
+/**
+ * Example of a store for Taverna Workflow Runs.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleNonpersistentRunStore implements RunStore {
+	private Map<String, TavernaRun> store = new HashMap<>();
+	private Object lock = new Object();
+
+	Timer timer;
+	private CleanerTask cleaner;
+
+	/**
+	 * The connection to the main policy store. Suitable for wiring up with
+	 * Spring.
+	 * 
+	 * @param p
+	 *            The policy to connect to.
+	 */
+	public void setPolicy(SimpleServerPolicy p) {
+		p.store = this;
+		cleanerIntervalUpdated(p.getCleanerInterval());
+	}
+
+	public SimpleNonpersistentRunStore() {
+		timer = new Timer("SimpleNonpersistentRunStore.CleanerTimer", true);
+		cleanerIntervalUpdated(300);
+	}
+
+	@Override
+	protected void finalize() {
+		timer.cancel();
+	}
+
+	/**
+	 * Remove and destroy all runs that are expired at the moment that this
+	 * method starts.
+	 */
+	void clean() {
+		Date now = new Date();
+		synchronized (lock) {
+			// Use an iterator so we have access to its remove() method...
+			Iterator<TavernaRun> i = store.values().iterator();
+			while (i.hasNext()) {
+				TavernaRun w = i.next();
+				if (w.getExpiry().before(now)) {
+					i.remove();
+					try {
+						w.destroy();
+					} catch (NoDestroyException e) {
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Reconfigure the cleaner task's call interval. This is called internally
+	 * and from the Policy when the interval is set there.
+	 * 
+	 * @param intervalInSeconds
+	 *            How long between runs of the cleaner task, in seconds.
+	 */
+	void cleanerIntervalUpdated(int intervalInSeconds) {
+		if (cleaner != null)
+			cleaner.cancel();
+		cleaner = new CleanerTask(this, intervalInSeconds);
+	}
+
+	@Override
+	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
+			throws UnknownRunException {
+		synchronized (lock) {
+			TavernaRun w = store.get(uuid);
+			if (w == null || !p.permitAccess(user, w))
+				throw new UnknownRunException();
+			return w;
+		}
+	}
+
+	@Override
+	public TavernaRun getRun(String uuid) throws UnknownRunException {
+		synchronized (lock) {
+			TavernaRun w = store.get(uuid);
+			if (w == null)
+				throw new UnknownRunException();
+			return w;
+		}
+	}
+
+	@Override
+	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
+		Map<String, TavernaRun> filtered = new HashMap<>();
+		synchronized (lock) {
+			for (Map.Entry<String, TavernaRun> entry : store.entrySet())
+				if (p.permitAccess(user, entry.getValue()))
+					filtered.put(entry.getKey(), entry.getValue());
+		}
+		return filtered;
+	}
+
+	@Override
+	public String registerRun(TavernaRun run) {
+		synchronized (lock) {
+			store.put(run.getId(), run);
+			return run.getId();
+		}
+	}
+
+	@Override
+	public void unregisterRun(String uuid) {
+		synchronized (lock) {
+			store.remove(uuid);
+		}
+	}
+}
+
+class CleanerTask extends TimerTask {
+	WeakReference<SimpleNonpersistentRunStore> store;
+
+	CleanerTask(SimpleNonpersistentRunStore store, int interval) {
+		this.store = new WeakReference<>(store);
+		int tms = interval * 1000;
+		store.timer.scheduleAtFixedRate(this, tms, tms);
+	}
+
+	@Override
+	public void run() {
+		SimpleNonpersistentRunStore s = store.get();
+		if (s != null) {
+			s.clean();
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
new file mode 100644
index 0000000..1a68d2c
--- /dev/null
+++ b/taverna-server-webapp/src/test/java/org/taverna/server/master/mocks/SimpleServerPolicy.java
@@ -0,0 +1,110 @@
+package org.taverna.server.master.mocks;
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * A very simple (and unsafe) security model. The number of runs is configurable
+ * through Spring (or 10 if unconfigured) with no per-user limits supported, all
+ * workflows are permitted, and all identified users may create a workflow run.
+ * Any user may read off information about any run, but only its owner may
+ * modify or destroy it.
+ * <p>
+ * Note that this is a <i>Policy Enforcement Point</i> for access control to
+ * individual workflows.
+ * 
+ * @author Donal Fellows
+ */
+public class SimpleServerPolicy implements Policy {
+	private int maxRuns = 10;
+	private int cleanerInterval;
+	SimpleNonpersistentRunStore store;
+
+	public void setMaxRuns(int maxRuns) {
+		this.maxRuns = maxRuns;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return maxRuns;
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal p) {
+		return null; // No per-user limits
+	}
+
+	public int getCleanerInterval() {
+		return cleanerInterval;
+	}
+
+	/**
+	 * Sets how often the store of workflow runs will try to clean out expired
+	 * runs.
+	 * 
+	 * @param intervalInSeconds
+	 */
+	public void setCleanerInterval(int intervalInSeconds) {
+		cleanerInterval = intervalInSeconds;
+		if (store != null)
+			store.cleanerIntervalUpdated(intervalInSeconds);
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal p, TavernaRun run) {
+		// No secrets here!
+		return true;
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal p, Workflow workflow)
+			throws NoCreateException {
+		// Only identified users may create
+		if (p == null)
+			throw new NoCreateException();
+		// Global run count limit enforcement
+		if (store.listRuns(p, this).size() >= maxRuns)
+			throw new NoCreateException();
+		// Per-user run count enforcement would come here
+	}
+
+	@Override
+	public void permitDestroy(UsernamePrincipal p, TavernaRun run)
+			throws NoDestroyException {
+		// Only the creator may destroy
+		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal p, TavernaRun run)
+			throws NoUpdateException {
+		// Only the creator may change
+		if (p == null || !p.equals(run.getSecurityContext().getOwner()))
+			throw new NoUpdateException();
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return 1;
+	}
+
+	@Override
+	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
+		return null;
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(UsernamePrincipal user,
+			List<URI> permitted) {
+		// Ignore
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/resources/example.xml
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/resources/example.xml b/taverna-server-webapp/src/test/resources/example.xml
new file mode 100644
index 0000000..14cc242
--- /dev/null
+++ b/taverna-server-webapp/src/test/resources/example.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+	<bean id="policy" class="org.taverna.server.master.mocks.SimpleServerPolicy"
+		lazy-init="false" scope="singleton">
+		<property name="maxRuns" value="1">
+			<description>
+				Limit on total number of simultaneous runs.
+			</description>
+		</property>
+		<property name="cleanerInterval" value="300">
+			<description>
+				Time between trying to delete expired runs, in seconds.
+			</description>
+		</property>
+	</bean>
+
+	<bean id="runFactory" class="org.taverna.server.master.mocks.ExampleRun$Builder">
+		<constructor-arg type="int" value="10" /> <!-- "initialLifetimeMinutes" -->
+	</bean>
+
+	<bean id="runCatalog" scope="singleton"
+		class="org.taverna.server.master.mocks.SimpleNonpersistentRunStore">
+		<property name="policy" ref="policy" />
+	</bean>
+
+	<bean id="listenerFactory" class="org.taverna.server.master.mocks.SimpleListenerFactory">
+		<property name="builders">
+			<description>
+				This map describes how to build each type of supported
+				event listener that is not installed by default. Any site policy for
+				a listeners should be installed using its properties, as shown. The
+				"key" is the type, the "class" is the builder for actual instances
+				(which must be an instance of
+				org.taverna.server.master.factories.SimpleListenerFactory.Builder)
+				and any policies and installation-specific configurations are
+				characterised by properties such as "sitePolicy" below.
+			</description>
+			<map>
+				<!--						<entry key="exampleListener">-->
+				<!--
+					<bean
+					class="org.taverna.server.master.example.ExampleListener$Builder">
+				-->
+				<!--								<property name="sitePolicy">-->
+				<!--									<value>Just an example!</value>-->
+				<!--								</property>-->
+				<!--							</bean>-->
+				<!--						</entry>-->
+			</map>
+		</property>
+	</bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/test/resources/log4j.properties b/taverna-server-webapp/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6707f55
--- /dev/null
+++ b/taverna-server-webapp/src/test/resources/log4j.properties
@@ -0,0 +1,4 @@
+log4j.rootLogger=info, R 
+log4j.appender.R=org.apache.log4j.ConsoleAppender
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-server-worker/pom.xml b/taverna-server-worker/pom.xml
new file mode 100644
index 0000000..8006c6d
--- /dev/null
+++ b/taverna-server-worker/pom.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna.server</groupId>
+		<artifactId>taverna-server</artifactId>
+		<version>3.1.0-incubating-SNAPSHOT</version>
+	</parent>
+	<artifactId>taverna-server-worker</artifactId>
+	<name>Apache Taverna Server Workflow Executor/File System Access Process Implementation</name>
+	<description>This is the implementation of the factory process that is started up by the web application to manage executing Taverna Workflow executeworkflow.sh calls. Also provides per-user access to filestore.</description>
+
+	<properties>
+		<workerMainClass>org.taverna.server.localworker.impl.TavernaRunManager</workerMainClass>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-runinterface</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-collections</groupId>
+			<artifactId>commons-collections</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>${project.parent.groupId}</groupId>
+			<artifactId>taverna-server-usagerecord</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-api</artifactId>
+			<version>${taverna.language.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-t2flow</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.taverna.language</groupId>
+			<artifactId>taverna-scufl2-wfbundle</artifactId>
+			<version>${taverna.language.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<configuration>
+					<descriptorRefs>
+						<descriptorRef>jar-with-dependencies</descriptorRef>
+					</descriptorRefs>
+					<archive>
+						<manifest>
+							<mainClass>${workerMainClass}</mainClass>
+						</manifest>
+					</archive>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.apache.maven.plugins</groupId>
+										<artifactId>maven-assembly-plugin</artifactId>
+                                    	<versionRange>[2.0,)</versionRange>
+                                    	<goals>
+                                    		<goal>single</goal>
+                                    	</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF b/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/taverna-server-worker/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: 
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
new file mode 100644
index 0000000..600913a
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Constants.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+import static java.nio.charset.Charset.defaultCharset;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * The defaults associated with this worker, together with various other
+ * constants.
+ * 
+ * @author Donal Fellows
+ */
+public abstract class Constants {
+	/**
+	 * Subdirectories of the working directory to create by default.
+	 */
+	public static final String[] SUBDIR_LIST = { "conf", "externaltool", "feed",
+			"interactions", "lib", "logs", "plugins", "repository", "var" };
+
+	/** The name of the default encoding for characters on this machine. */
+	public static final String SYSTEM_ENCODING = defaultCharset().name();
+
+	/**
+	 * Password to use to encrypt security information. This default is <7 chars
+	 * to work even without Unlimited Strength JCE.
+	 */
+	public static final char[] KEYSTORE_PASSWORD = { 'c', 'h', 'a', 'n', 'g', 'e' };
+
+	/**
+	 * The name of the directory (in the home directory) where security settings
+	 * will be written.
+	 */
+	public static final String SECURITY_DIR_NAME = ".taverna-server-security";
+
+	/** The name of the file that will be the created keystore. */
+	public static final String KEYSTORE_FILE = "t2keystore.ubr";
+
+	/** The name of the file that will be the created truststore. */
+	public static final String TRUSTSTORE_FILE = "t2truststore.ubr";
+
+	/**
+	 * The name of the file that contains the password to unlock the keystore
+	 * and truststore.
+	 */
+	public static final String PASSWORD_FILE = "password.txt";
+
+	// --------- UNUSED ---------
+	// /**
+	// * The name of the file that contains the mapping from URIs to keystore
+	// * aliases.
+	// */
+	// public static final String URI_ALIAS_MAP = "urlmap.txt";
+
+	/**
+	 * Used to instruct the Taverna credential manager to use a non-default
+	 * location for user credentials.
+	 */
+	public static final String CREDENTIAL_MANAGER_DIRECTORY = "-cmdir";
+
+	/**
+	 * Used to instruct the Taverna credential manager to take its master
+	 * password from standard input.
+	 */
+	public static final String CREDENTIAL_MANAGER_PASSWORD = "-cmpassword";
+
+	/**
+	 * Name of environment variable used to pass HELIO security tokens to
+	 * workflows.
+	 */
+	// This technique is known to be insecure; bite me.
+	public static final String HELIO_TOKEN_NAME = "HELIO_CIS_TOKEN";
+
+	/**
+	 * The name of the standard listener, which is installed by default.
+	 */
+	public static final String DEFAULT_LISTENER_NAME = "io";
+
+	/**
+	 * Time to wait for the subprocess to wait, in milliseconds.
+	 */
+	public static final int START_WAIT_TIME = 1500;
+
+	/**
+	 * Time to wait for success or failure of a death-causing activity (i.e.,
+	 * sending a signal).
+	 */
+	public static final int DEATH_TIME = 333;
+
+	/**
+	 * The name of the file (in this code's resources) that provides the default
+	 * security policy that we use.
+	 */
+	public static final String SECURITY_POLICY_FILE = "security.policy";
+
+	/**
+	 * The Java property holding security policy info.
+	 */
+	public static final String SEC_POLICY_PROP = "java.security.policy";
+	/**
+	 * The Java property to set to make this code not try to enforce security
+	 * policy.
+	 */
+	public static final String UNSECURE_PROP = "taverna.suppressrestrictions.rmi";
+	/**
+	 * The Java property that holds the name of the host name to enforce.
+	 */
+	public static final String RMI_HOST_PROP = "java.rmi.server.hostname";
+	/**
+	 * The default hostname to require in secure mode. This is the
+	 * <i>resolved</i> version of "localhost".
+	 */
+	public static final String LOCALHOST;
+	static {
+		String h = "127.0.0.1"; // fallback
+		try {
+			h = InetAddress.getByName("localhost").getHostAddress();
+		} catch (UnknownHostException e) {
+			e.printStackTrace();
+		} finally {
+			LOCALHOST = h;
+		}
+	}
+
+	/**
+	 * Time to wait during closing down this process. In milliseconds.
+	 */
+	public static final int DEATH_DELAY = 500;
+	/**
+	 * The name of the property describing where shared directories should be
+	 * located.
+	 */
+	public static final String SHARED_DIR_PROP = "taverna.sharedDirectory";
+
+	public static final String TIME = "/usr/bin/time";
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
new file mode 100644
index 0000000..3896c06
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/RunAccounting.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+/**
+ * 
+ * @author Donal Fellows
+ */
+public interface RunAccounting {
+	/**
+	 * Logs that a run has started executing.
+	 */
+	void runStarted();
+
+	/**
+	 * Logs that a run has finished executing.
+	 */
+	void runCeased();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
new file mode 100644
index 0000000..c513ed8
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/Worker.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.api;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import org.taverna.server.localworker.impl.LocalWorker;
+import org.taverna.server.localworker.remote.ImplementationException;
+import org.taverna.server.localworker.remote.RemoteListener;
+import org.taverna.server.localworker.remote.RemoteStatus;
+import org.taverna.server.localworker.server.UsageRecordReceiver;
+
+/**
+ * The interface between the connectivity layer and the thunk to the
+ * subprocesses.
+ * 
+ * @author Donal Fellows
+ */
+public interface Worker {
+	/**
+	 * Fire up the workflow. This causes a transition into the operating state.
+	 * 
+	 * @param local
+	 *            The reference to the factory class for this worker.
+	 * @param executeWorkflowCommand
+	 *            The command to run to execute the workflow.
+	 * @param workflow
+	 *            The workflow document to execute.
+	 * @param workingDir
+	 *            What directory to use as the working directory.
+	 * @param inputBaclavaFile
+	 *            The baclava file to use for inputs, or <tt>null</tt> to use
+	 *            the other <b>input*</b> arguments' values.
+	 * @param inputRealFiles
+	 *            A mapping of input names to files that supply them. Note that
+	 *            we assume that nothing mapped here will be mapped in
+	 *            <b>inputValues</b>.
+	 * @param inputValues
+	 *            A mapping of input names to values to supply to them. Note
+	 *            that we assume that nothing mapped here will be mapped in
+	 *            <b>inputFiles</b>.
+	 * @param inputDelimiters
+	 *            A mapping of input names to characters used to split them into
+	 *            lists.
+	 * @param outputBaclavaFile
+	 *            What baclava file to write the output from the workflow into,
+	 *            or <tt>null</tt> to have it written into the <tt>out</tt>
+	 *            subdirectory.
+	 * @param contextDirectory
+	 *            The directory containing the keystore and truststore. <i>Must
+	 *            not be <tt>null</tt>.</i>
+	 * @param keystorePassword
+	 *            The password to the keystore and truststore. <i>Must not be
+	 *            <tt>null</tt>.</i>
+	 * @param generateProvenance
+	 *            Whether to generate a run bundle containing provenance data.
+	 * @param environment
+	 *            Any environment variables that need to be added to the
+	 *            invokation.
+	 * @param masterToken
+	 *            The internal name of the workflow run.
+	 * @param runtimeSettings
+	 *            List of configuration details for the forked runtime.
+	 * @return Whether a successful start happened.
+	 * @throws Exception
+	 *             If any of quite a large number of things goes wrong.
+	 */
+	boolean initWorker(LocalWorker local, String executeWorkflowCommand,
+			byte[] workflow, File workingDir, File inputBaclavaFile,
+			Map<String, File> inputRealFiles, Map<String, String> inputValues,
+			Map<String, String> inputDelimiters, File outputBaclavaFile,
+			File contextDirectory, char[] keystorePassword,
+			boolean generateProvenance, Map<String, String> environment,
+			String masterToken, List<String> runtimeSettings) throws Exception;
+
+	/**
+	 * Kills off the subprocess if it exists and is alive.
+	 * 
+	 * @throws Exception
+	 *             if anything goes badly wrong when the worker is being killed
+	 *             off.
+	 */
+	void killWorker() throws Exception;
+
+	/**
+	 * Move the worker out of the stopped state and back to operating.
+	 * 
+	 * @throws Exception
+	 *             if it fails (which it always does; operation currently
+	 *             unsupported).
+	 */
+	void startWorker() throws Exception;
+
+	/**
+	 * Move the worker into the stopped state from the operating state.
+	 * 
+	 * @throws Exception
+	 *             if it fails (which it always does; operation currently
+	 *             unsupported).
+	 */
+	void stopWorker() throws Exception;
+
+	/**
+	 * @return The status of the workflow run. Note that this can be an
+	 *         expensive operation.
+	 */
+	RemoteStatus getWorkerStatus();
+
+	/**
+	 * @return The listener that is registered by default, in addition to all
+	 *         those that are explicitly registered by the user.
+	 */
+	RemoteListener getDefaultListener();
+
+	/**
+	 * @param receiver
+	 *            The destination where any final usage records are to be
+	 *            written in order to log them back to the server.
+	 */
+	void setURReceiver(UsageRecordReceiver receiver);
+
+	/**
+	 * Arrange for the deletion of any resources created during worker process
+	 * construction. Guaranteed to be the last thing done before finalization.
+	 * 
+	 * @throws ImplementationException
+	 *             If anything goes wrong.
+	 */
+	void deleteLocalResources() throws ImplementationException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
new file mode 100644
index 0000000..4ce13a7
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/api/WorkerFactory.java
@@ -0,0 +1,18 @@
+package org.taverna.server.localworker.api;
+
+
+/**
+ * Class that manufactures instances of {@link Worker}.
+ * 
+ * @author Donal Fellows
+ */
+public interface WorkerFactory {
+	/**
+	 * Create an instance of the low-level worker class.
+	 * 
+	 * @return The worker object.
+	 * @throws Exception
+	 *             If anything goes wrong.
+	 */
+	Worker makeInstance() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
new file mode 100644
index 0000000..1692856
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/DirectoryDelegate.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static org.apache.commons.io.FileUtils.forceDelete;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+import static org.apache.commons.io.FileUtils.touch;
+import static org.taverna.server.localworker.impl.utils.FilenameVerifier.getValidatedNewFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.collections.MapIterator;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the workflow run's working
+ * directory and its subdirectories.
+ * 
+ * @author Donal Fellows
+ * @see FileDelegate
+ */
+@SuppressWarnings("serial")
+public class DirectoryDelegate extends UnicastRemoteObject implements
+		RemoteDirectory {
+	private File dir;
+	private DirectoryDelegate parent;
+	private ReferenceMap localCache;
+
+	/**
+	 * @param dir
+	 * @param parent
+	 * @throws RemoteException
+	 *             If registration of the directory fails.
+	 */
+	public DirectoryDelegate(@Nonnull File dir,
+			@Nonnull DirectoryDelegate parent) throws RemoteException {
+		super();
+		this.localCache = new ReferenceMap();
+		this.dir = dir;
+		this.parent = parent;
+	}
+
+	@Override
+	public Collection<RemoteDirectoryEntry> getContents()
+			throws RemoteException {
+		List<RemoteDirectoryEntry> result = new ArrayList<>();
+		for (String s : dir.list()) {
+			if (s.equals(".") || s.equals(".."))
+				continue;
+			File f = new File(dir, s);
+			RemoteDirectoryEntry entry;
+			synchronized (localCache) {
+				entry = (RemoteDirectoryEntry) localCache.get(s);
+				if (f.isDirectory()) {
+					if (entry == null || !(entry instanceof DirectoryDelegate)) {
+						entry = new DirectoryDelegate(f, this);
+						localCache.put(s, entry);
+					}
+				} else if (f.isFile()) {
+					if (entry == null || !(entry instanceof FileDelegate)) {
+						entry = new FileDelegate(f, this);
+						localCache.put(s, entry);
+					}
+				} else {
+					// not file or dir; skip...
+					continue;
+				}
+			}
+			result.add(entry);
+		}
+		return result;
+	}
+
+	@Override
+	public RemoteFile makeEmptyFile(String name) throws IOException {
+		File f = getValidatedNewFile(dir, name);
+		touch(f);
+		FileDelegate delegate = new FileDelegate(f, this);
+		synchronized (localCache) {
+			localCache.put(name, delegate);
+		}
+		return delegate;
+	}
+
+	@Override
+	public RemoteDirectory makeSubdirectory(String name) throws IOException {
+		File f = getValidatedNewFile(dir, name);
+		forceMkdir(f);
+		DirectoryDelegate delegate = new DirectoryDelegate(f, this);
+		synchronized (localCache) {
+			localCache.put(name, delegate);
+		}
+		return delegate;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public void destroy() throws IOException {
+		if (parent == null)
+			throw new IOException("tried to destroy main job working directory");
+		Collection<RemoteDirectoryEntry> values;
+		synchronized (localCache) {
+			values = new ArrayList<>(localCache.values());
+		}
+		for (RemoteDirectoryEntry obj : values) {
+			if (obj == null)
+				continue;
+			try {
+				obj.destroy();
+			} catch (IOException e) {
+			}
+		}
+		forceDelete(dir);
+		parent.forgetEntry(this);
+	}
+
+	@Override
+	public RemoteDirectory getContainingDirectory() {
+		return parent;
+	}
+
+	void forgetEntry(@Nonnull RemoteDirectoryEntry entry) {
+		synchronized (localCache) {
+			MapIterator i = localCache.mapIterator();
+			while (i.hasNext()) {
+				Object key = i.next();
+				if (entry == i.getValue()) {
+					localCache.remove(key);
+					break;
+				}
+			}
+		}
+	}
+
+	@Override
+	public String getName() {
+		if (parent == null)
+			return "";
+		return dir.getName();
+	}
+
+	@Override
+	public Date getModificationDate() throws RemoteException {
+		return new Date(dir.lastModified());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
----------------------------------------------------------------------
diff --git a/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
new file mode 100644
index 0000000..7e47af9
--- /dev/null
+++ b/taverna-server-worker/src/main/java/org/taverna/server/localworker/impl/FileDelegate.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.localworker.impl;
+
+import static java.lang.System.arraycopy;
+import static java.net.InetAddress.getLocalHost;
+import static org.apache.commons.io.FileUtils.copyFile;
+import static org.apache.commons.io.FileUtils.forceDelete;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+
+import org.taverna.server.localworker.remote.RemoteDirectory;
+import org.taverna.server.localworker.remote.RemoteFile;
+
+/**
+ * This class acts as a remote-aware delegate for the files in a workflow run's
+ * working directory and its subdirectories.
+ * 
+ * @author Donal Fellows
+ * @see DirectoryDelegate
+ */
+@java.lang.SuppressWarnings("serial")
+public class FileDelegate extends UnicastRemoteObject implements RemoteFile {
+	private File file;
+	private DirectoryDelegate parent;
+
+	/**
+	 * @param file
+	 * @param parent
+	 * @throws RemoteException
+	 *             If registration of the file fails.
+	 */
+	public FileDelegate(@Nonnull File file, @Nonnull DirectoryDelegate parent)
+			throws RemoteException {
+		super();
+		this.file = file;
+		this.parent = parent;
+	}
+
+	@Override
+	public byte[] getContents(int offset, int length) throws IOException {
+		if (length == -1)
+			length = (int) (file.length() - offset);
+		if (length < 0 || length > 1024 * 64)
+			length = 1024 * 64;
+		byte[] buffer = new byte[length];
+		int read;
+		try (FileInputStream fis = new FileInputStream(file)) {
+			if (offset > 0 && fis.skip(offset) != offset)
+				throw new IOException("did not move to correct offset in file");
+			read = fis.read(buffer);
+		}
+		if (read <= 0)
+			return new byte[0];
+		if (read < buffer.length) {
+			byte[] shortened = new byte[read];
+			arraycopy(buffer, 0, shortened, 0, read);
+			return shortened;
+		}
+		return buffer;
+	}
+
+	@Override
+	public long getSize() {
+		return file.length();
+	}
+
+	@Override
+	public void setContents(byte[] data) throws IOException {
+		try (FileOutputStream fos = new FileOutputStream(file)) {
+			fos.write(data);
+		}
+	}
+
+	@Override
+	public void appendContents(byte[] data) throws IOException {
+		try (FileOutputStream fos = new FileOutputStream(file, true)) {
+			fos.write(data);
+		}
+	}
+
+	@Override
+	public void destroy() throws IOException {
+		forceDelete(file);
+		parent.forgetEntry(this);
+		parent = null;
+	}
+
+	@Override
+	public RemoteDirectory getContainingDirectory() {
+		return parent;
+	}
+
+	@Override
+	public String getName() {
+		return file.getName();
+	}
+
+	@Override
+	public void copy(RemoteFile sourceFile) throws RemoteException, IOException {
+		String sourceHost = sourceFile.getNativeHost();
+		if (!getNativeHost().equals(sourceHost)) {
+			throw new IOException(
+					"cross-system copy not implemented; cannot copy from "
+							+ sourceHost + " to " + getNativeHost());
+		}
+		// Must copy; cannot count on other file to stay unmodified
+		copyFile(new File(sourceFile.getNativeName()), file);
+	}
+
+	@Override
+	public String getNativeName() {
+		return file.getAbsolutePath();
+	}
+
+	@Override
+	public String getNativeHost() {
+		try {
+			return getLocalHost().getHostAddress();
+		} catch (UnknownHostException e) {
+			throw new RuntimeException(
+					"unexpected failure to resolve local host address", e);
+		}
+	}
+
+	@Override
+	public Date getModificationDate() throws RemoteException {
+		return new Date(file.lastModified());
+	}
+}


[33/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
deleted file mode 100644
index 22158d5..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RemoteRunDelegate.java
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.lang.System.currentTimeMillis;
-import static java.util.Calendar.MINUTE;
-import static java.util.Collections.sort;
-import static java.util.Collections.unmodifiableSet;
-import static java.util.UUID.randomUUID;
-import static org.apache.commons.io.IOUtils.closeQuietly;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.worker.RemoteRunDelegate.checkBadFilename;
-import static org.taverna.server.master.worker.RunConnection.NAME_LENGTH;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.PipedOutputStream;
-import java.rmi.MarshalledObject;
-import java.rmi.RemoteException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-
-import javax.annotation.Nonnull;
-
-import org.apache.commons.logging.Log;
-import org.taverna.server.localworker.remote.IllegalStateTransitionException;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteDirectory;
-import org.taverna.server.localworker.remote.RemoteDirectoryEntry;
-import org.taverna.server.localworker.remote.RemoteFile;
-import org.taverna.server.localworker.remote.RemoteInput;
-import org.taverna.server.localworker.remote.RemoteListener;
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.localworker.remote.RemoteStatus;
-import org.taverna.server.localworker.remote.StillWorkingOnItException;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.common.Workflow;
-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.NoListenerException;
-import org.taverna.server.master.exceptions.OverloadedException;
-import org.taverna.server.master.exceptions.UnknownRunException;
-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.SecurityContextFactory;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Bridging shim between the WebApp world and the RMI world.
- * 
- * @author Donal Fellows
- */
-@SuppressWarnings("serial")
-public class RemoteRunDelegate implements TavernaRun {
-	private transient Log log = getLog("Taverna.Server.Worker");
-	transient TavernaSecurityContext secContext;
-	Date creationInstant;
-	Workflow workflow;
-	Date expiry;
-	HashSet<String> readers;
-	HashSet<String> writers;
-	HashSet<String> destroyers;
-	transient String id;
-	transient RemoteSingleRun run;
-	transient RunDBSupport db;
-	transient FactoryBean factory;
-	boolean doneTransitionToFinished;
-	boolean generateProvenance;// FIXME expose
-	String name;
-	private static final String ELLIPSIS = "...";
-
-	public RemoteRunDelegate(Date creationInstant, Workflow workflow,
-			RemoteSingleRun rsr, int defaultLifetime, RunDBSupport db, UUID id,
-			boolean generateProvenance, FactoryBean factory) {
-		if (rsr == null)
-			throw new IllegalArgumentException("remote run must not be null");
-		this.creationInstant = creationInstant;
-		this.workflow = workflow;
-		Calendar c = Calendar.getInstance();
-		c.add(MINUTE, defaultLifetime);
-		this.expiry = c.getTime();
-		this.run = rsr;
-		this.db = db;
-		this.generateProvenance = generateProvenance;
-		this.factory = factory;
-		try {
-			this.name = "";
-			String ci = " " + creationInstant;
-			String n = workflow.getName();
-			if (n.length() > NAME_LENGTH - ci.length())
-				n = n.substring(0,
-						NAME_LENGTH - ci.length() - ELLIPSIS.length())
-						+ ELLIPSIS;
-			this.name = n + ci;
-		} catch (Exception e) {
-			// Ignore; it's just a name, not something important.
-		}
-		if (id != null)
-			this.id = id.toString();
-	}
-
-	RemoteRunDelegate() {
-	}
-
-	/**
-	 * Get the types of listener supported by this run.
-	 * 
-	 * @return A list of listener type names.
-	 * @throws RemoteException
-	 *             If anything goes wrong.
-	 */
-	public List<String> getListenerTypes() throws RemoteException {
-		return run.getListenerTypes();
-	}
-
-	@Override
-	public void addListener(Listener listener) {
-		if (listener instanceof ListenerDelegate)
-			try {
-				run.addListener(((ListenerDelegate) listener).getRemote());
-			} catch (RemoteException e) {
-				log.warn("communication problem adding listener", e);
-			} catch (ImplementationException e) {
-				log.warn("implementation problem adding listener", e);
-			}
-		else
-			log.fatal("bad listener " + listener.getClass()
-					+ "; not applicable remotely!");
-	}
-
-	@Override
-	public String getId() {
-		if (id == null)
-			id = randomUUID().toString();
-		return id;
-	}
-
-	/**
-	 * Attach a listener to a workflow run and return its local delegate.
-	 * 
-	 * @param type
-	 *            The type of listener to create.
-	 * @param config
-	 *            The configuration of the listener.
-	 * @return The local delegate of the listener.
-	 * @throws NoListenerException
-	 *             If anything goes wrong.
-	 */
-	public Listener makeListener(String type, String config)
-			throws NoListenerException {
-		try {
-			return new ListenerDelegate(run.makeListener(type, config));
-		} catch (RemoteException e) {
-			throw new NoListenerException("failed to make listener", e);
-		}
-	}
-
-	@Override
-	public void destroy() {
-		try {
-			run.destroy();
-		} catch (RemoteException | ImplementationException e) {
-			log.warn("failed to destroy run", e);
-		}
-	}
-
-	@Override
-	public Date getExpiry() {
-		return new Date(expiry.getTime());
-	}
-
-	@Override
-	public List<Listener> getListeners() {
-		List<Listener> listeners = new ArrayList<>();
-		try {
-			for (RemoteListener rl : run.getListeners())
-				listeners.add(new ListenerDelegate(rl));
-		} catch (RemoteException e) {
-			log.warn("failed to get listeners", e);
-		}
-		return listeners;
-	}
-
-	@Override
-	public TavernaSecurityContext getSecurityContext() {
-		return secContext;
-	}
-
-	@Override
-	public Status getStatus() {
-		try {
-			switch (run.getStatus()) {
-			case Initialized:
-				return Status.Initialized;
-			case Operating:
-				return Status.Operating;
-			case Stopped:
-				return Status.Stopped;
-			case Finished:
-				return Status.Finished;
-			}
-		} catch (RemoteException e) {
-			log.warn("problem getting remote status", e);
-		}
-		return Status.Finished;
-	}
-
-	@Override
-	public Workflow getWorkflow() {
-		return workflow;
-	}
-
-	@Override
-	public Directory getWorkingDirectory() throws FilesystemAccessException {
-		try {
-			return new DirectoryDelegate(run.getWorkingDirectory());
-		} catch (Throwable e) {
-			if (e.getCause() != null)
-				e = e.getCause();
-			throw new FilesystemAccessException(
-					"problem getting main working directory handle", e);
-		}
-	}
-
-	@Override
-	public void setExpiry(Date d) {
-		if (d.after(new Date()))
-			expiry = new Date(d.getTime());
-		db.flushToDisk(this);
-	}
-
-	@Override
-	public String setStatus(Status s) throws BadStateChangeException {
-		try {
-			log.info("setting status of run " + id + " to " + s);
-			switch (s) {
-			case Initialized:
-				run.setStatus(RemoteStatus.Initialized);
-				break;
-			case Operating:
-				if (run.getStatus() == RemoteStatus.Initialized) {
-					if (!factory.isAllowingRunsToStart())
-						throw new OverloadedException();
-					secContext.conveySecurity();
-				}
-				run.setGenerateProvenance(generateProvenance);
-				run.setStatus(RemoteStatus.Operating);
-				factory.getMasterEventFeed()
-						.started(
-								this,
-								"started run execution",
-								"The execution of run '" + getName()
-										+ "' has started.");
-				break;
-			case Stopped:
-				run.setStatus(RemoteStatus.Stopped);
-				break;
-			case Finished:
-				run.setStatus(RemoteStatus.Finished);
-				break;
-			}
-			return null;
-		} catch (IllegalStateTransitionException e) {
-			throw new BadStateChangeException(e.getMessage());
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e.getMessage(), e.getCause());
-		} catch (GeneralSecurityException | IOException e) {
-			throw new BadStateChangeException(e.getMessage(), e);
-		} catch (ImplementationException e) {
-			if (e.getCause() != null)
-				throw new BadStateChangeException(e.getMessage(), e.getCause());
-			throw new BadStateChangeException(e.getMessage(), e);
-		} catch (StillWorkingOnItException e) {
-			log.info("still working on setting status of run " + id + " to "
-					+ s, e);
-			return e.getMessage();
-		} catch (InterruptedException e) {
-			throw new BadStateChangeException(
-					"interrupted while waiting to insert notification into database");
-		}
-	}
-
-	static void checkBadFilename(String filename)
-			throws FilesystemAccessException {
-		if (filename.startsWith("/"))
-			throw new FilesystemAccessException("filename may not be absolute");
-		if (Arrays.asList(filename.split("/")).contains(".."))
-			throw new FilesystemAccessException(
-					"filename may not refer to parent");
-	}
-
-	@Override
-	public String getInputBaclavaFile() {
-		try {
-			return run.getInputBaclavaFile();
-		} catch (RemoteException e) {
-			log.warn("problem when fetching input baclava file", e);
-			return null;
-		}
-	}
-
-	@Override
-	public List<Input> getInputs() {
-		ArrayList<Input> inputs = new ArrayList<>();
-		try {
-			for (RemoteInput ri : run.getInputs())
-				inputs.add(new RunInput(ri));
-		} catch (RemoteException e) {
-			log.warn("problem when fetching list of workflow inputs", e);
-		}
-		return inputs;
-	}
-
-	@Override
-	public String getOutputBaclavaFile() {
-		try {
-			return run.getOutputBaclavaFile();
-		} catch (RemoteException e) {
-			log.warn("problem when fetching output baclava file", e);
-			return null;
-		}
-	}
-
-	@Override
-	public Input makeInput(String name) throws BadStateChangeException {
-		try {
-			return new RunInput(run.makeInput(name));
-		} catch (RemoteException e) {
-			throw new BadStateChangeException("failed to make input", e);
-		}
-	}
-
-	@Override
-	public void setInputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		checkBadFilename(filename);
-		try {
-			run.setInputBaclavaFile(filename);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException(
-					"cannot set input baclava file name", e);
-		}
-	}
-
-	@Override
-	public void setOutputBaclavaFile(String filename)
-			throws FilesystemAccessException, BadStateChangeException {
-		checkBadFilename(filename);
-		try {
-			run.setOutputBaclavaFile(filename);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException(
-					"cannot set output baclava file name", e);
-		}
-	}
-
-	@Override
-	public Date getCreationTimestamp() {
-		return creationInstant == null ? null : new Date(
-				creationInstant.getTime());
-	}
-
-	@Override
-	public Date getFinishTimestamp() {
-		try {
-			return run.getFinishTimestamp();
-		} catch (RemoteException e) {
-			log.info("failed to get finish timestamp", e);
-			return null;
-		}
-	}
-
-	@Override
-	public Date getStartTimestamp() {
-		try {
-			return run.getStartTimestamp();
-		} catch (RemoteException e) {
-			log.info("failed to get finish timestamp", e);
-			return null;
-		}
-	}
-
-	/**
-	 * @param readers
-	 *            the readers to set
-	 */
-	public void setReaders(Set<String> readers) {
-		this.readers = new HashSet<>(readers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the readers
-	 */
-	public Set<String> getReaders() {
-		return readers == null ? new HashSet<String>()
-				: unmodifiableSet(readers);
-	}
-
-	/**
-	 * @param writers
-	 *            the writers to set
-	 */
-	public void setWriters(Set<String> writers) {
-		this.writers = new HashSet<>(writers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the writers
-	 */
-	public Set<String> getWriters() {
-		return writers == null ? new HashSet<String>()
-				: unmodifiableSet(writers);
-	}
-
-	/**
-	 * @param destroyers
-	 *            the destroyers to set
-	 */
-	public void setDestroyers(Set<String> destroyers) {
-		this.destroyers = new HashSet<>(destroyers);
-		db.flushToDisk(this);
-	}
-
-	/**
-	 * @return the destroyers
-	 */
-	public Set<String> getDestroyers() {
-		return destroyers == null ? new HashSet<String>()
-				: unmodifiableSet(destroyers);
-	}
-
-	private void writeObject(ObjectOutputStream out) throws IOException {
-		out.defaultWriteObject();
-		out.writeUTF(secContext.getOwner().getName());
-		out.writeObject(secContext.getFactory());
-		out.writeObject(new MarshalledObject<>(run));
-	}
-
-	@Override
-	public boolean getGenerateProvenance() {
-		return generateProvenance;
-	}
-
-	@Override
-	public void setGenerateProvenance(boolean generateProvenance) {
-		this.generateProvenance = generateProvenance;
-		db.flushToDisk(this);
-	}
-
-	@SuppressWarnings("unchecked")
-	private void readObject(ObjectInputStream in) throws IOException,
-			ClassNotFoundException {
-		in.defaultReadObject();
-		if (log == null)
-			log = getLog("Taverna.Server.LocalWorker");
-		final String creatorName = in.readUTF();
-		SecurityContextFactory factory = (SecurityContextFactory) in
-				.readObject();
-		try {
-			secContext = factory.create(this,
-					new UsernamePrincipal(creatorName));
-		} catch (RuntimeException | IOException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new SecurityContextReconstructionException(e);
-		}
-		run = ((MarshalledObject<RemoteSingleRun>) in.readObject()).get();
-	}
-
-	public void setSecurityContext(TavernaSecurityContext tavernaSecurityContext) {
-		secContext = tavernaSecurityContext;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public void setName(@Nonnull String name) {
-		if (name.length() > RunConnection.NAME_LENGTH)
-			this.name = name.substring(0, RunConnection.NAME_LENGTH);
-		else
-			this.name = name;
-		db.flushToDisk(this);
-	}
-
-	@Override
-	public void ping() throws UnknownRunException {
-		try {
-			run.ping();
-		} catch (RemoteException e) {
-			throw new UnknownRunException(e);
-		}
-	}
-}
-
-abstract class DEDelegate implements DirectoryEntry {
-	Log log = getLog("Taverna.Server.Worker");
-	private RemoteDirectoryEntry entry;
-	private String name;
-	private String full;
-	private Date cacheModTime;
-	private long cacheQueryTime = 0L;
-
-	DEDelegate(RemoteDirectoryEntry entry) {
-		this.entry = entry;
-	}
-
-	@Override
-	public void destroy() throws FilesystemAccessException {
-		try {
-			entry.destroy();
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to delete directory entry", e);
-		}
-	}
-
-	@Override
-	public String getFullName() {
-		if (full != null)
-			return full;
-		String n = getName();
-		RemoteDirectoryEntry re = entry;
-		try {
-			while (true) {
-				RemoteDirectory parent = re.getContainingDirectory();
-				if (parent == null)
-					break;
-				n = parent.getName() + "/" + n;
-				re = parent;
-			}
-		} catch (RemoteException e) {
-			log.warn("failed to generate full name", e);
-		}
-		return (full = n);
-	}
-
-	@Override
-	public String getName() {
-		if (name == null)
-			try {
-				name = entry.getName();
-			} catch (RemoteException e) {
-				log.error("failed to get name", e);
-			}
-		return name;
-	}
-
-	@Override
-	public Date getModificationDate() {
-		if (cacheModTime == null || currentTimeMillis() - cacheQueryTime < 5000)
-			try {
-				cacheModTime = entry.getModificationDate();
-				cacheQueryTime = currentTimeMillis();
-			} catch (RemoteException e) {
-				log.error("failed to get modification time", e);
-			}
-		return cacheModTime;
-	}
-
-	@Override
-	public int compareTo(DirectoryEntry de) {
-		return getFullName().compareTo(de.getFullName());
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		return o != null && o instanceof DEDelegate
-				&& getFullName().equals(((DEDelegate) o).getFullName());
-	}
-
-	@Override
-	public int hashCode() {
-		return getFullName().hashCode();
-	}
-}
-
-class DirectoryDelegate extends DEDelegate implements Directory {
-	RemoteDirectory rd;
-
-	DirectoryDelegate(RemoteDirectory dir) {
-		super(dir);
-		rd = dir;
-	}
-
-	@Override
-	public Collection<DirectoryEntry> getContents()
-			throws FilesystemAccessException {
-		ArrayList<DirectoryEntry> result = new ArrayList<>();
-		try {
-			for (RemoteDirectoryEntry rde : rd.getContents()) {
-				if (rde instanceof RemoteDirectory)
-					result.add(new DirectoryDelegate((RemoteDirectory) rde));
-				else
-					result.add(new FileDelegate((RemoteFile) rde));
-			}
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to get directory contents", e);
-		}
-		return result;
-	}
-
-	@Override
-	public Collection<DirectoryEntry> getContentsByDate()
-			throws FilesystemAccessException {
-		ArrayList<DirectoryEntry> result = new ArrayList<>(getContents());
-		sort(result, new DateComparator());
-		return result;
-	}
-
-	static class DateComparator implements Comparator<DirectoryEntry> {
-		@Override
-		public int compare(DirectoryEntry a, DirectoryEntry b) {
-			return a.getModificationDate().compareTo(b.getModificationDate());
-		}
-	}
-
-	@Override
-	public File makeEmptyFile(Principal actor, String name)
-			throws FilesystemAccessException {
-		try {
-			return new FileDelegate(rd.makeEmptyFile(name));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to make empty file", e);
-		}
-	}
-
-	@Override
-	public Directory makeSubdirectory(Principal actor, String name)
-			throws FilesystemAccessException {
-		try {
-			return new DirectoryDelegate(rd.makeSubdirectory(name));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to make subdirectory",
-					e);
-		}
-	}
-
-	@Override
-	public ZipStream getContentsAsZip() throws FilesystemAccessException {
-		ZipStream zs = new ZipStream();
-
-		final ZipOutputStream zos;
-		try {
-			zos = new ZipOutputStream(new PipedOutputStream(zs));
-		} catch (IOException e) {
-			throw new FilesystemAccessException("problem building zip stream",
-					e);
-		}
-		Thread t = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					zipDirectory(rd, null, zos);
-				} catch (IOException e) {
-					log.warn("problem when zipping directory", e);
-				} finally {
-					closeQuietly(zos);
-				}
-			}
-		});
-		t.setDaemon(true);
-		t.start();
-		return zs;
-	}
-
-	/**
-	 * Compresses a directory tree into a ZIP.
-	 * 
-	 * @param dir
-	 *            The directory to compress.
-	 * @param base
-	 *            The base name of the directory (or <tt>null</tt> if this is
-	 *            the root directory of the ZIP).
-	 * @param zos
-	 *            Where to write the compressed data.
-	 * @throws RemoteException
-	 *             If some kind of problem happens with the remote delegates.
-	 * @throws IOException
-	 *             If we run into problems with reading or writing data.
-	 */
-	void zipDirectory(RemoteDirectory dir, String base, ZipOutputStream zos)
-			throws RemoteException, IOException {
-		for (RemoteDirectoryEntry rde : dir.getContents()) {
-			String name = rde.getName();
-			if (base != null)
-				name = base + "/" + name;
-			if (rde instanceof RemoteDirectory) {
-				RemoteDirectory rd = (RemoteDirectory) rde;
-				zipDirectory(rd, name, zos);
-			} else {
-				RemoteFile rf = (RemoteFile) rde;
-				zos.putNextEntry(new ZipEntry(name));
-				try {
-					int off = 0;
-					while (true) {
-						byte[] c = rf.getContents(off, 64 * 1024);
-						if (c == null || c.length == 0)
-							break;
-						zos.write(c);
-						off += c.length;
-					}
-				} finally {
-					zos.closeEntry();
-				}
-			}
-		}
-	}
-}
-
-class FileDelegate extends DEDelegate implements File {
-	RemoteFile rf;
-
-	FileDelegate(RemoteFile f) {
-		super(f);
-		this.rf = f;
-	}
-
-	@Override
-	public byte[] getContents(int offset, int length)
-			throws FilesystemAccessException {
-		try {
-			return rf.getContents(offset, length);
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to read file contents",
-					e);
-		}
-	}
-
-	@Override
-	public long getSize() throws FilesystemAccessException {
-		try {
-			return rf.getSize();
-		} catch (IOException e) {
-			throw new FilesystemAccessException("failed to get file length", e);
-		}
-	}
-
-	@Override
-	public void setContents(byte[] data) throws FilesystemAccessException {
-		try {
-			rf.setContents(data);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to write file contents", e);
-		}
-	}
-
-	@Override
-	public void appendContents(byte[] data) throws FilesystemAccessException {
-		try {
-			rf.appendContents(data);
-		} catch (IOException e) {
-			throw new FilesystemAccessException(
-					"failed to write file contents", e);
-		}
-	}
-
-	@Override
-	public void copy(File from) throws FilesystemAccessException {
-		FileDelegate fromFile;
-		try {
-			fromFile = (FileDelegate) from;
-		} catch (ClassCastException e) {
-			throw new FilesystemAccessException("different types of File?!");
-		}
-
-		try {
-			rf.copy(fromFile.rf);
-		} catch (Exception e) {
-			throw new FilesystemAccessException("failed to copy file contents",
-					e);
-		}
-		return;
-	}
-}
-
-class ListenerDelegate implements Listener {
-	private Log log = getLog("Taverna.Server.Worker");
-	private RemoteListener r;
-	String conf;
-
-	ListenerDelegate(RemoteListener l) {
-		r = l;
-	}
-
-	RemoteListener getRemote() {
-		return r;
-	}
-
-	@Override
-	public String getConfiguration() {
-		try {
-			if (conf == null)
-				conf = r.getConfiguration();
-		} catch (RemoteException e) {
-			log.warn("failed to get configuration", e);
-		}
-		return conf;
-	}
-
-	@Override
-	public String getName() {
-		try {
-			return r.getName();
-		} catch (RemoteException e) {
-			log.warn("failed to get name", e);
-			return "UNKNOWN NAME";
-		}
-	}
-
-	@Override
-	public String getProperty(String propName) throws NoListenerException {
-		try {
-			return r.getProperty(propName);
-		} catch (RemoteException e) {
-			throw new NoListenerException("no such property: " + propName, e);
-		}
-	}
-
-	@Override
-	public String getType() {
-		try {
-			return r.getType();
-		} catch (RemoteException e) {
-			log.warn("failed to get type", e);
-			return "UNKNOWN TYPE";
-		}
-	}
-
-	@Override
-	public String[] listProperties() {
-		try {
-			return r.listProperties();
-		} catch (RemoteException e) {
-			log.warn("failed to list properties", e);
-			return new String[0];
-		}
-	}
-
-	@Override
-	public void setProperty(String propName, String value)
-			throws NoListenerException, BadPropertyValueException {
-		try {
-			r.setProperty(propName, value);
-		} catch (RemoteException e) {
-			log.warn("failed to set property", e);
-			if (e.getCause() != null
-					&& e.getCause() instanceof RuntimeException)
-				throw new NoListenerException("failed to set property",
-						e.getCause());
-			if (e.getCause() != null && e.getCause() instanceof Exception)
-				throw new BadPropertyValueException("failed to set property",
-						e.getCause());
-			throw new BadPropertyValueException("failed to set property", e);
-		}
-	}
-}
-
-class RunInput implements Input {
-	private final RemoteInput i;
-
-	RunInput(RemoteInput remote) {
-		this.i = remote;
-	}
-
-	@Override
-	public String getFile() {
-		try {
-			return i.getFile();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public String getName() {
-		try {
-			return i.getName();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public String getValue() {
-		try {
-			return i.getValue();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public void setFile(String file) throws FilesystemAccessException,
-			BadStateChangeException {
-		checkBadFilename(file);
-		try {
-			i.setFile(file);
-		} catch (RemoteException e) {
-			throw new FilesystemAccessException("cannot set file for input", e);
-		}
-	}
-
-	@Override
-	public void setValue(String value) throws BadStateChangeException {
-		try {
-			i.setValue(value);
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e);
-		}
-	}
-
-	@Override
-	public String getDelimiter() {
-		try {
-			return i.getDelimiter();
-		} catch (RemoteException e) {
-			return null;
-		}
-	}
-
-	@Override
-	public void setDelimiter(String delimiter) throws BadStateChangeException {
-		try {
-			if (delimiter != null)
-				delimiter = delimiter.substring(0, 1);
-			i.setDelimiter(delimiter);
-		} catch (RemoteException e) {
-			throw new BadStateChangeException(e);
-		}
-	}
-}
-
-@SuppressWarnings("serial")
-class SecurityContextReconstructionException extends RuntimeException {
-	public SecurityContextReconstructionException(Throwable t) {
-		super("failed to rebuild security context", t);
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
deleted file mode 100644
index cf55ea0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RunConnection.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static org.taverna.server.master.worker.RunConnection.COUNT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.NAMES_QUERY;
-import static org.taverna.server.master.worker.RunConnection.SCHEMA;
-import static org.taverna.server.master.worker.RunConnection.TABLE;
-import static org.taverna.server.master.worker.RunConnection.TIMEOUT_QUERY;
-import static org.taverna.server.master.worker.RunConnection.UNTERMINATED_QUERY;
-
-import java.io.IOException;
-import java.rmi.MarshalledObject;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.jdo.annotations.Column;
-import javax.jdo.annotations.Join;
-import javax.jdo.annotations.PersistenceCapable;
-import javax.jdo.annotations.Persistent;
-import javax.jdo.annotations.PrimaryKey;
-import javax.jdo.annotations.Queries;
-import javax.jdo.annotations.Query;
-
-import org.taverna.server.localworker.remote.RemoteSingleRun;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.common.Workflow;
-import org.taverna.server.master.interfaces.SecurityContextFactory;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The representation of the connections to the runs that actually participates
- * in the persistence system.
- * 
- * @author Donal Fellows
- */
-@PersistenceCapable(table = TABLE, schema = SCHEMA)
-@Queries({
-		@Query(name = "count", language = "SQL", value = COUNT_QUERY, unique = "true", resultClass = Integer.class),
-		@Query(name = "names", language = "SQL", value = NAMES_QUERY, unique = "false", resultClass = String.class),
-		@Query(name = "unterminated", language = "SQL", value = UNTERMINATED_QUERY, unique = "false", resultClass = String.class),
-		@Query(name = "timedout", language = "SQL", value = TIMEOUT_QUERY, unique = "false", resultClass = String.class) })
-public class RunConnection {
-	static final String SCHEMA = "TAVERNA";
-	static final String TABLE = "RUN_CONNECTION";
-	private static final String FULL_NAME = SCHEMA + "." + TABLE;
-	static final String COUNT_QUERY = "SELECT count(*) FROM " + FULL_NAME;
-	static final String NAMES_QUERY = "SELECT ID FROM " + FULL_NAME;
-	static final String TIMEOUT_QUERY = "SELECT ID FROM " + FULL_NAME
-			+ "   WHERE expiry < CURRENT_TIMESTAMP";
-	static final String UNTERMINATED_QUERY = "SELECT ID FROM " + FULL_NAME
-			+ "   WHERE doneTransitionToFinished = 0";
-	static final int NAME_LENGTH = 48; 
-
-	@PrimaryKey
-	@Column(length = 40)
-	private String id;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = NAME_LENGTH)
-	private String name;
-
-	@Persistent(defaultFetchGroup = "true")
-	private Date creationInstant;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Workflow workflow;
-
-	@Persistent(defaultFetchGroup = "true")
-	private Date expiry;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_READERS", column = "ID")
-	private String[] readers;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_WRITERS", column = "ID")
-	private String[] writers;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Join(table = TABLE + "_DESTROYERS", column = "ID")
-	private String[] destroyers;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private MarshalledObject<RemoteSingleRun> run;
-
-	@Persistent(defaultFetchGroup = "true")
-	private int doneTransitionToFinished;
-
-	@Persistent(defaultFetchGroup = "true")
-	private int generateProvenance;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = 128)
-	String owner;
-
-	@Persistent(defaultFetchGroup = "true")
-	@Column(length = 36)
-	private String securityToken;
-
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private SecurityContextFactory securityContextFactory;
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Credential[] credentials;
-	@Persistent(defaultFetchGroup = "true", serialized = "true")
-	@Column(jdbcType = "BLOB", sqlType = "BLOB")
-	private Trust[] trust;
-
-	private static final String[] STRING_ARY = new String[0];
-
-	public String getId() {
-		return id;
-	}
-
-	public boolean isFinished() {
-		return doneTransitionToFinished != 0;
-	}
-
-	public void setFinished(boolean finished) {
-		doneTransitionToFinished = (finished ? 1 : 0);
-	}
-
-	public boolean isProvenanceGenerated() {
-		return generateProvenance != 0;
-	}
-
-	public void setProvenanceGenerated(boolean generate) {
-		generateProvenance = (generate ? 1 : 0);
-	}
-
-	/**
-	 * Manufacture a persistent representation of the given workflow run. Must
-	 * be called within the context of a transaction.
-	 * 
-	 * @param rrd
-	 *            The remote delegate of the workflow run.
-	 * @return The persistent object.
-	 * @throws IOException
-	 *             If serialisation fails.
-	 */
-	@Nonnull
-	public static RunConnection toDBform(@Nonnull RemoteRunDelegate rrd)
-			throws IOException {
-		RunConnection rc = new RunConnection();
-		rc.id = rrd.id;
-		rc.makeChanges(rrd);
-		return rc;
-	}
-
-	private static List<String> list(String[] ary) {
-		if (ary == null)
-			return emptyList();
-		return asList(ary);
-	}
-
-	/**
-	 * Get the remote run delegate for a particular persistent connection. Must
-	 * be called within the context of a transaction.
-	 * 
-	 * @param db
-	 *            The database facade.
-	 * @return The delegate object.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nonnull
-	public RemoteRunDelegate fromDBform(@Nonnull RunDBSupport db)
-			throws Exception {
-		RemoteRunDelegate rrd = new RemoteRunDelegate();
-		rrd.id = getId();
-		rrd.creationInstant = creationInstant;
-		rrd.workflow = workflow;
-		rrd.expiry = expiry;
-		rrd.readers = new HashSet<>(list(readers));
-		rrd.writers = new HashSet<>(list(writers));
-		rrd.destroyers = new HashSet<>(list(destroyers));
-		rrd.run = run.get();
-		rrd.doneTransitionToFinished = isFinished();
-		rrd.generateProvenance = isProvenanceGenerated();
-		rrd.secContext = securityContextFactory.create(rrd,
-				new UsernamePrincipal(owner));
-		((SecurityContextDelegate)rrd.secContext).setCredentialsAndTrust(credentials,trust);
-		rrd.db = db;
-		rrd.factory = db.getFactory();
-		rrd.name = name;
-		return rrd;
-	}
-
-	/**
-	 * Flush changes from a remote run delegate to the database. Must be called
-	 * within the context of a transaction.
-	 * 
-	 * @param rrd
-	 *            The remote run delegate object that has potential changes.
-	 * @throws IOException
-	 *             If anything goes wrong in serialization.
-	 */
-	public void makeChanges(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		// Properties that are set exactly once
-		if (creationInstant == null) {
-			creationInstant = rrd.getCreationTimestamp();
-			workflow = rrd.getWorkflow();
-			run = new MarshalledObject<>(rrd.run);
-			securityContextFactory = rrd.getSecurityContext().getFactory();
-			owner = rrd.getSecurityContext().getOwner().getName();
-			securityToken = ((org.taverna.server.master.worker.SecurityContextFactory) securityContextFactory)
-					.issueNewPassword();
-		}
-		// Properties that are set multiple times
-		expiry = rrd.getExpiry();
-		readers = rrd.getReaders().toArray(STRING_ARY);
-		writers = rrd.getWriters().toArray(STRING_ARY);
-		destroyers = rrd.getDestroyers().toArray(STRING_ARY);
-		credentials = rrd.getSecurityContext().getCredentials();
-		trust = rrd.getSecurityContext().getTrusted();
-		if (rrd.name.length() > NAME_LENGTH)
-			this.name = rrd.name.substring(0, NAME_LENGTH);
-		else
-			this.name = rrd.name;
-		setFinished(rrd.doneTransitionToFinished);
-		setProvenanceGenerated(rrd.generateProvenance);
-	}
-
-	public String getSecurityToken() {
-		return securityToken;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
deleted file mode 100644
index 2aa7ed1..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDBSupport.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.taverna.server.master.notification.NotificationEngine;
-
-/**
- * The interface to the database of runs.
- * 
- * @author Donal Fellows
- */
-public interface RunDBSupport {
-	/**
-	 * Scan each run to see if it has finished yet and issue registered
-	 * notifications if it has.
-	 */
-	void checkForFinishNow();
-
-	/**
-	 * Remove currently-expired runs from this database.
-	 */
-	void cleanNow();
-
-	/**
-	 * How many runs are stored in the database.
-	 * 
-	 * @return The current size of the run table.
-	 */
-	int countRuns();
-
-	/**
-	 * Ensure that a run gets persisted in the database. It is assumed that the
-	 * value is already in there.
-	 * 
-	 * @param run
-	 *            The run to persist.
-	 */
-	void flushToDisk(@Nonnull RemoteRunDelegate run);
-
-	/**
-	 * Select an arbitrary representative run.
-	 * 
-	 * @return The selected run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nullable
-	RemoteRunDelegate pickArbitraryRun() throws Exception;
-
-	/**
-	 * Get a list of all the run names.
-	 * 
-	 * @return The names (i.e., UUIDs) of all the runs.
-	 */
-	@Nonnull
-	List<String> listRunNames();
-
-	/**
-	 * @param notificationEngine
-	 *            A reference to the notification fabric bean.
-	 */
-	void setNotificationEngine(NotificationEngine notificationEngine);
-
-	/**
-	 * @param notifier
-	 *            A reference to the bean that creates messages about workflow
-	 *            run termination.
-	 */
-	void setNotifier(CompletionNotifier notifier);
-
-	/**
-	 * @return A reference to the actual factory for remote runs.
-	 */
-	FactoryBean getFactory();
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
deleted file mode 100644
index cedb4b5..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabase.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.lang.Integer.parseInt;
-import static java.util.UUID.randomUUID;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.UUID;
-
-import javax.annotation.Nullable;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.Status;
-import org.taverna.server.master.exceptions.UnknownRunException;
-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.notification.NotificationEngine;
-import org.taverna.server.master.notification.NotificationEngine.Message;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * The main facade bean that interfaces to the database of runs.
- * 
- * @author Donal Fellows
- */
-public class RunDatabase implements RunStore, RunDBSupport {
-	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
-	RunDatabaseDAO dao;
-	CompletionNotifier backupNotifier;
-	Map<String, CompletionNotifier> typedNotifiers;
-	private NotificationEngine notificationEngine;
-	@Autowired
-	private FactoryBean factory;
-	private Map<String, TavernaRun> cache = new HashMap<>();
-
-	@Override
-	@Required
-	public void setNotifier(CompletionNotifier n) {
-		backupNotifier = n;
-	}
-
-	public void setTypeNotifiers(List<CompletionNotifier> notifiers) {
-		typedNotifiers = new HashMap<>();
-		for (CompletionNotifier n : notifiers)
-			typedNotifiers.put(n.getName(), n);
-	}
-
-	@Required
-	@Override
-	public void setNotificationEngine(NotificationEngine notificationEngine) {
-		this.notificationEngine = notificationEngine;
-	}
-
-	@Required
-	public void setDao(RunDatabaseDAO dao) {
-		this.dao = dao;
-	}
-
-	@Override
-	public void checkForFinishNow() {
-		/*
-		 * Get which runs are actually newly finished; this requires getting the
-		 * candidates from the database and *then* doing the expensive requests
-		 * to the back end to find out the status.
-		 */
-		Map<String, RemoteRunDelegate> notifiable = new HashMap<>();
-		for (RemoteRunDelegate p : dao.getPotentiallyNotifiable())
-			if (p.getStatus() == Status.Finished)
-				notifiable.put(p.getId(), p);
-
-		// Check if there's nothing more to do
-		if (notifiable.isEmpty())
-			return;
-
-		/*
-		 * Tell the database about the ones we've got.
-		 */
-		dao.markFinished(notifiable.keySet());
-
-		/*
-		 * Send out the notifications. The notification addresses are stored in
-		 * the back-end engine, so this is *another* thing that can take time.
-		 */
-		for (RemoteRunDelegate rrd : notifiable.values())
-			for (Listener l : rrd.getListeners())
-				if (l.getName().equals("io")) {
-					try {
-						notifyFinished(rrd.id, l, rrd);
-					} catch (Exception e) {
-						log.warn("failed to do notification of completion", e);
-					}
-					break;
-				}
-	}
-
-	@Override
-	public void cleanNow() {
-		List<String> cleaned;
-		try {
-			cleaned = dao.doClean();
-		} catch (Exception e) {
-			log.warn("failure during deletion of expired runs", e);
-			return;
-		}
-		synchronized (cache) {
-			for (String id : cleaned)
-				cache.remove(id);
-		}
-	}
-
-	@Override
-	public int countRuns() {
-		return dao.countRuns();
-	}
-
-	@Override
-	public void flushToDisk(RemoteRunDelegate run) {
-		try {
-			dao.flushToDisk(run);
-		} catch (IOException e) {
-			throw new RuntimeException(
-					"unexpected problem when persisting run record in database",
-					e);
-		}
-	}
-
-	@Override
-	public RemoteRunDelegate pickArbitraryRun() throws Exception {
-		return dao.pickArbitraryRun();
-	}
-
-	@Override
-	public List<String> listRunNames() {
-		return dao.listRunNames();
-	}
-
-	@Nullable
-	private TavernaRun get(String uuid) {
-		TavernaRun run = null;
-		synchronized (cache) {
-			run = cache.get(uuid);
-		}
-		try {
-			if (run != null)
-				run.ping();
-		} catch (UnknownRunException e) {
-			if (log.isDebugEnabled())
-				log.debug("stale mapping in cache?", e);
-			// Don't need to flush the cache; this happens when cleaning anyway
-			run = null;
-		}
-		if (run == null)
-			run = dao.get(uuid);
-		return run;
-	}
-
-	@Override
-	public TavernaRun getRun(UsernamePrincipal user, Policy p, String uuid)
-			throws UnknownRunException {
-		// Check first to see if the 'uuid' actually looks like a UUID; if
-		// not, throw it out immediately without logging an exception.
-		try {
-			UUID.fromString(uuid);
-		} catch (IllegalArgumentException e) {
-			if (log.isDebugEnabled())
-				log.debug("run ID does not look like UUID; rejecting...");
-			throw new UnknownRunException();
-		}
-		TavernaRun run = get(uuid);
-		if (run != null && (user == null || p.permitAccess(user, run)))
-			return run;
-		throw new UnknownRunException();
-	}
-
-	@Override
-	public TavernaRun getRun(String uuid) throws UnknownRunException {
-		TavernaRun run = get(uuid);
-		if (run != null)
-			return run;
-		throw new UnknownRunException();
-	}
-
-	@Override
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		synchronized (cache) {
-			Map<String, TavernaRun> cached = new HashMap<>();
-			for (Entry<String, TavernaRun> e : cache.entrySet()) {
-				TavernaRun r = e.getValue();
-				if (p.permitAccess(user, r))
-					cached.put(e.getKey(), r);
-			}
-			if (!cached.isEmpty())
-				return cached;
-		}
-		return dao.listRuns(user, p);
-	}
-
-	private void logLength(String message, Object obj) {
-		if (!log.isDebugEnabled())
-			return;
-		try {
-			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
-				oos.writeObject(obj);
-			}
-			log.debug(message + ": " + baos.size());
-		} catch (Exception e) {
-			log.warn("oops", e);
-		}
-	}
-
-	@Override
-	public String registerRun(TavernaRun run) {
-		if (!(run instanceof RemoteRunDelegate))
-			throw new IllegalArgumentException(
-					"run must be created by localworker package");
-		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
-		if (rrd.id == null)
-			rrd.id = randomUUID().toString();
-		logLength("RemoteRunDelegate serialized length", rrd);
-		try {
-			dao.persistRun(rrd);
-		} catch (IOException e) {
-			throw new RuntimeException(
-					"unexpected problem when persisting run record in database",
-					e);
-		}
-		synchronized (cache) {
-			cache.put(rrd.getId(), run);
-		}
-		return rrd.getId();
-	}
-
-	@Override
-	public void unregisterRun(String uuid) {
-		try {
-			if (dao.unpersistRun(uuid))
-				synchronized (cache) {
-					cache.remove(uuid);
-				}
-		} catch (RuntimeException e) {
-			if (log.isDebugEnabled())
-				log.debug("problem persisting the deletion of the run " + uuid,
-						e);
-		}
-	}
-
-	/**
-	 * Process the event that a run has finished.
-	 * 
-	 * @param name
-	 *            The name of the run.
-	 * @param io
-	 *            The io listener of the run (used to get information about the
-	 *            run).
-	 * @param run
-	 *            The handle to the run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	private void notifyFinished(final String name, Listener io,
-			final RemoteRunDelegate run) throws Exception {
-		String to = io.getProperty("notificationAddress");
-		final int code;
-		try {
-			code = parseInt(io.getProperty("exitcode"));
-		} catch (NumberFormatException nfe) {
-			// Ignore; not much we can do here...
-			return;
-		}
-
-		notificationEngine.dispatchMessage(run, to, new Message() {
-			private CompletionNotifier getNotifier(String type) {
-				CompletionNotifier n = typedNotifiers.get(type);
-				if (n == null)
-					n = backupNotifier;
-				return n;
-			}
-
-			@Override
-			public String getContent(String type) {
-				return getNotifier(type).makeCompletionMessage(name, run, code);
-			}
-
-			@Override
-			public String getTitle(String type) {
-				return getNotifier(type).makeMessageSubject(name, run, code);
-			}
-		});
-	}
-
-	@Override
-	public FactoryBean getFactory() {
-		return factory;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
deleted file mode 100644
index 51931c0..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RunDatabaseDAO.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static org.taverna.server.master.worker.RunConnection.toDBform;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.jdo.annotations.PersistenceAware;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.interfaces.Policy;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.utils.CallTimeLogger.PerfLogged;
-import org.taverna.server.master.utils.JDOSupport;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * This handles storing runs, interfacing with the underlying state engine as
- * necessary.
- * 
- * @author Donal Fellows
- */
-@PersistenceAware
-public class RunDatabaseDAO extends JDOSupport<RunConnection> {
-	public RunDatabaseDAO() {
-		super(RunConnection.class);
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Worker.RunDB");
-	private RunDatabase facade;
-
-	@Required
-	public void setFacade(RunDatabase facade) {
-		this.facade = facade;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-	@SuppressWarnings("unchecked")
-	private List<String> nameRuns() {
-		if (log.isDebugEnabled())
-			log.debug("fetching all run names");
-		return (List<String>) namedQuery("names").execute();
-	}
-
-	/**
-	 * @return The number of workflow runs in the database.
-	 */
-	@WithinSingleTransaction
-	public int countRuns() {
-		if (log.isDebugEnabled())
-			log.debug("counting the number of runs");
-		return (Integer) namedQuery("count").execute();
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> expiredRuns() {
-		return (List<String>) namedQuery("timedout").execute();
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<String> unterminatedRuns() {
-		return (List<String>) namedQuery("unterminated").execute();
-	}
-
-	@Nullable
-	private RunConnection pickRun(@Nonnull String name) {
-		if (log.isDebugEnabled())
-			log.debug("fetching the run called " + name);
-		try {
-			RunConnection rc = getById(name);
-			if (rc == null)
-				log.warn("no result for " + name);
-			return rc;
-		} catch (RuntimeException e) {
-			log.warn("problem in fetch", e);
-			throw e;
-		}
-	}
-
-	@Nullable
-	@WithinSingleTransaction
-	public String getSecurityToken(@Nonnull String name) {
-		RunConnection rc = getById(name);
-		if (rc == null)
-			return null;
-		return rc.getSecurityToken();
-	}
-
-	private void persist(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		persist(toDBform(rrd));
-	}
-
-	@Nonnull
-	private List<RunConnection> allRuns() {
-		try {
-			List<RunConnection> rcs = new ArrayList<>();
-			List<String> names = nameRuns();
-			for (String id : names) {
-				try {
-					if (id != null)
-						rcs.add(pickRun(id));
-				} catch (RuntimeException e) {
-					continue;
-				}
-			}
-			return rcs;
-		} catch (RuntimeException e) {
-			log.warn("problem in fetch", e);
-			throw e;
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-
-	/**
-	 * Obtain a workflow run handle.
-	 * 
-	 * @param name
-	 *            The identifier of the run.
-	 * @return The run handle, or <tt>null</tt> if there is no such run.
-	 */
-	@Nullable
-	@WithinSingleTransaction
-	public TavernaRun get(String name) {
-		try {
-			RunConnection rc = pickRun(name);
-			return (rc == null) ? null : rc.fromDBform(facade);
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Get the runs that a user can read things from.
-	 * 
-	 * @param user
-	 *            Who is asking?
-	 * @param p
-	 *            The policy that determines what they can see.
-	 * @return A mapping from run IDs to run handles.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public Map<String, TavernaRun> listRuns(UsernamePrincipal user, Policy p) {
-		Map<String, TavernaRun> result = new HashMap<>();
-		for (String id : nameRuns())
-			try {
-				RemoteRunDelegate rrd = pickRun(id).fromDBform(facade);
-				if (p.permitAccess(user, rrd))
-					result.put(id, rrd);
-			} catch (Exception e) {
-				continue;
-			}
-		return result;
-	}
-
-	/**
-	 * @return A list of the IDs for all workflow runs.
-	 */
-	@Nonnull
-	@WithinSingleTransaction
-	public List<String> listRunNames() {
-		List<String> runNames = new ArrayList<>();
-		for (RunConnection rc : allRuns())
-			if (rc.getId() != null)
-				runNames.add(rc.getId());
-		return runNames;
-	}
-
-	/**
-	 * @return An arbitrary, representative workflow run.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Nullable
-	@WithinSingleTransaction
-	public RemoteRunDelegate pickArbitraryRun() throws Exception {
-		for (RunConnection rc : allRuns()) {
-			if (rc.getId() == null)
-				continue;
-			return rc.fromDBform(facade);
-		}
-		return null;
-	}
-
-	/**
-	 * Make a workflow run persistent. Must only be called once per workflow
-	 * run.
-	 * 
-	 * @param rrd
-	 *            The workflow run to persist.
-	 * @throws IOException
-	 *             If anything goes wrong with serialisation of the run.
-	 */
-	@WithinSingleTransaction
-	public void persistRun(@Nonnull RemoteRunDelegate rrd) throws IOException {
-		persist(rrd);
-	}
-
-	/**
-	 * Stop a workflow run from being persistent.
-	 * 
-	 * @param name
-	 *            The ID of the run.
-	 * @return Whether a deletion happened.
-	 */
-	@WithinSingleTransaction
-	public boolean unpersistRun(String name) {
-		RunConnection rc = pickRun(name);
-		if (rc != null)
-			delete(rc);
-		return rc != null;
-	}
-
-	/**
-	 * Ensure that the given workflow run is synchronized with the database.
-	 * 
-	 * @param run
-	 *            The run to synchronise.
-	 * @throws IOException
-	 *             If serialization of anything fails.
-	 */
-	@WithinSingleTransaction
-	public void flushToDisk(@Nonnull RemoteRunDelegate run) throws IOException {
-		getById(run.id).makeChanges(run);
-	}
-
-	/**
-	 * Remove all workflow runs that have expired.
-	 * 
-	 * @return The ids of the deleted runs.
-	 */
-	@Nonnull
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<String> doClean() {
-		if (log.isDebugEnabled())
-			log.debug("deleting runs that timed out before " + new Date());
-		List<String> toDelete = expiredRuns();
-		if (log.isDebugEnabled())
-			log.debug("found " + toDelete.size() + " runs to delete");
-		for (String id : toDelete) {
-			RunConnection rc = getById(id);
-			try {
-				rc.fromDBform(facade).run.destroy();
-			} catch (Exception e) {
-				if (log.isDebugEnabled())
-					log.debug("failed to delete execution resource for " + id,
-							e);
-			}
-			delete(rc);
-		}
-		return toDelete;
-	}
-
-	/**
-	 * @return A list of workflow runs that are candidates for doing
-	 *         notification of termination.
-	 */
-	@Nonnull
-	@PerfLogged
-	@WithinSingleTransaction
-	public List<RemoteRunDelegate> getPotentiallyNotifiable() {
-		List<RemoteRunDelegate> toNotify = new ArrayList<>();
-		for (String id : unterminatedRuns())
-			try {
-				RunConnection rc = getById(id);
-				toNotify.add(rc.fromDBform(facade));
-			} catch (Exception e) {
-				log.warn("failed to fetch connection token"
-						+ "for notification of completion check", e);
-			}
-		return toNotify;
-	}
-
-	@PerfLogged
-	@WithinSingleTransaction
-	public void markFinished(@Nonnull Set<String> terminated) {
-		for (String id : terminated) {
-			RunConnection rc = getById(id);
-			if (rc == null)
-				continue;
-			try {
-				rc.fromDBform(facade).doneTransitionToFinished = true;
-				rc.setFinished(true);
-			} catch (Exception e) {
-				log.warn("failed to note termination", e);
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java b/server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
deleted file mode 100644
index 29ac884..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/RunFactoryConfiguration.java
+++ /dev/null
@@ -1,395 +0,0 @@
-package org.taverna.server.master.worker;
-
-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 java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.annotation.Order;
-import org.springframework.jmx.export.annotation.ManagedAttribute;
-import org.springframework.jmx.export.annotation.ManagedMetric;
-import org.springframework.jmx.export.annotation.ManagedResource;
-import org.taverna.server.master.factories.ConfigurableRunFactory;
-import org.taverna.server.master.localworker.LocalWorkerState;
-
-@ManagedResource(objectName = JMX_ROOT + "Factory", description = "The factory for runs.")
-public abstract class RunFactoryConfiguration implements ConfigurableRunFactory {
-	protected Log log = LogFactory.getLog("Taverna.Server.Worker");
-	protected LocalWorkerState state;
-	protected RunDBSupport runDB;
-	private int totalRuns = 0;
-
-	@PreDestroy
-	void closeLog() {
-		log = null;
-	}
-
-	@Autowired(required = true)
-	@Order(0)
-	void setState(LocalWorkerState state) {
-		this.state = state;
-	}
-
-	@Autowired(required = true)
-	@Order(0)
-	void setRunDB(RunDBSupport runDB) {
-		this.runDB = runDB;
-	}
-
-	/**
-	 * Drop any current references to the registry of runs, and kill off that
-	 * process.
-	 */
-	protected abstract void reinitRegistry();
-
-	/**
-	 * Drop any current references to the run factory subprocess and kill it
-	 * off.
-	 */
-	protected abstract void reinitFactory();
-
-	/** Count the number of operating runs. */
-	protected abstract int operatingCount() throws Exception;
-
-	protected final synchronized void incrementRunCount() {
-		totalRuns++;
-	}
-
-	@Override
-	@ManagedAttribute(description = "Whether it is allowed to start a run executing.", currencyTimeLimit = 30)
-	public final boolean isAllowingRunsToStart() {
-		try {
-			return state.getOperatingLimit() > getOperatingCount();
-		} catch (Exception e) {
-			log.info("failed to get operating run count", e);
-			return false;
-		}
-	}
-
-	@Override
-	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
-	public final String getRegistryHost() {
-		return state.getRegistryHost();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The host holding the RMI registry to communicate via.")
-	public final void setRegistryHost(String host) {
-		state.setRegistryHost(host);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
-	public final int getRegistryPort() {
-		return state.getRegistryPort();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The port number of the RMI registry. Should not normally be set.")
-	public final void setRegistryPort(int port) {
-		state.setRegistryPort(port);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
-	public final String getRmiRegistryJar() {
-		return state.getRegistryJar();
-	}
-
-	@Override
-	@ManagedAttribute(description = "What JAR do we use to start the RMI registry process?")
-	public final void setRmiRegistryJar(String rmiRegistryJar) {
-		state.setRegistryJar(rmiRegistryJar);
-		reinitRegistry();
-		reinitFactory();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
-	public final int getMaxRuns() {
-		return state.getMaxRuns();
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous runs supported by the server.", currencyTimeLimit = 300)
-	public final void setMaxRuns(int maxRuns) {
-		state.setMaxRuns(maxRuns);
-	}
-
-	/** @return How many minutes should a workflow live by default? */
-	@Override
-	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
-	public final int getDefaultLifetime() {
-		return state.getDefaultLifetime();
-	}
-
-	/**
-	 * Set how long a workflow should live by default.
-	 * 
-	 * @param defaultLifetime
-	 *            Default lifetime, in minutes.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many minutes should a workflow live by default?", currencyTimeLimit = 300)
-	public final void setDefaultLifetime(int defaultLifetime) {
-		state.setDefaultLifetime(defaultLifetime);
-	}
-
-	/**
-	 * @return How many milliseconds to wait between checks to see if a worker
-	 *         process has registered.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
-	public final int getSleepTime() {
-		return state.getSleepMS();
-	}
-
-	/**
-	 * @param sleepTime
-	 *            How many milliseconds to wait between checks to see if a
-	 *            worker process has registered.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many milliseconds to wait between checks to see if a worker process has registered.", currencyTimeLimit = 300)
-	public final void setSleepTime(int sleepTime) {
-		state.setSleepMS(sleepTime);
-	}
-
-	/**
-	 * @return How many seconds to wait for a worker process to register itself.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
-	public final int getWaitSeconds() {
-		return state.getWaitSeconds();
-	}
-
-	/**
-	 * @param seconds
-	 *            How many seconds to wait for a worker process to register
-	 *            itself.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many seconds to wait for a worker process to register itself.", currencyTimeLimit = 300)
-	public final void setWaitSeconds(int seconds) {
-		state.setWaitSeconds(seconds);
-	}
-
-	/** @return The script to run to start running a workflow. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
-	public final String getExecuteWorkflowScript() {
-		return state.getExecuteWorkflowScript();
-	}
-
-	/**
-	 * @param executeWorkflowScript
-	 *            The script to run to start running a workflow.
-	 */
-	@Override
-	@ManagedAttribute(description = "The script to run to start running a workflow.", currencyTimeLimit = 300)
-	public final void setExecuteWorkflowScript(String executeWorkflowScript) {
-		state.setExecuteWorkflowScript(executeWorkflowScript);
-		reinitFactory();
-	}
-
-	/** @return The location of the JAR implementing the server worker processes. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
-	public final String getServerWorkerJar() {
-		return state.getServerWorkerJar();
-	}
-
-	/**
-	 * @param serverWorkerJar
-	 *            The location of the JAR implementing the server worker
-	 *            processes.
-	 */
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the server worker processes.")
-	public final void setServerWorkerJar(String serverWorkerJar) {
-		state.setServerWorkerJar(serverWorkerJar);
-		reinitFactory();
-	}
-
-	/** @return The list of additional arguments used to make a worker process. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
-	public final String[] getExtraArguments() {
-		return state.getExtraArgs();
-	}
-
-	/**
-	 * @param extraArguments
-	 *            The list of additional arguments used to make a worker
-	 *            process.
-	 */
-	@Override
-	@ManagedAttribute(description = "The list of additional arguments used to make a worker process.", currencyTimeLimit = 300)
-	public final void setExtraArguments(@Nonnull String[] extraArguments) {
-		state.setExtraArgs(extraArguments);
-		reinitFactory();
-	}
-
-	/** @return Which java executable to run. */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
-	public final String getJavaBinary() {
-		return state.getJavaBinary();
-	}
-
-	/**
-	 * @param javaBinary
-	 *            Which java executable to run.
-	 */
-	@Override
-	@ManagedAttribute(description = "Which java executable to run.", currencyTimeLimit = 300)
-	public final void setJavaBinary(@Nonnull String javaBinary) {
-		state.setJavaBinary(javaBinary);
-		reinitFactory();
-	}
-
-	/**
-	 * @return A file containing a password to use when running a program as
-	 *         another user (e.g., with sudo).
-	 */
-	@Nullable
-	@Override
-	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
-	public final String getPasswordFile() {
-		return state.getPasswordFile();
-	}
-
-	/**
-	 * @param passwordFile
-	 *            A file containing a password to use when running a program as
-	 *            another user (e.g., with sudo).
-	 */
-	@Override
-	@ManagedAttribute(description = "A file containing a password to use when running a program as another user (e.g., with sudo).", currencyTimeLimit = 300)
-	public final void setPasswordFile(@Nullable String passwordFile) {
-		state.setPasswordFile(passwordFile);
-		reinitFactory();
-	}
-
-	/**
-	 * @return The location of the JAR implementing the secure-fork process.
-	 */
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
-	public final String getServerForkerJar() {
-		return state.getServerForkerJar();
-	}
-
-	/**
-	 * @param serverForkerJar
-	 *            The location of the JAR implementing the secure-fork process.
-	 */
-	@Override
-	@ManagedAttribute(description = "The location of the JAR implementing the secure-fork process.", currencyTimeLimit = 300)
-	public final void setServerForkerJar(String forkerJarFilename) {
-		state.setServerForkerJar(forkerJarFilename);
-		reinitFactory();
-	}
-
-	/**
-	 * @return How many times has a workflow run been spawned by this engine.
-	 *         Restarts reset this counter.
-	 */
-	@Override
-	@ManagedMetric(description = "How many times has a workflow run been spawned by this engine.", currencyTimeLimit = 10, metricType = COUNTER, category = "throughput")
-	public final synchronized int getTotalRuns() {
-		return totalRuns;
-	}
-
-	/**
-	 * @return How many checks were done for the worker process the last time a
-	 *         spawn was tried.
-	 */
-	@Override
-	@ManagedAttribute(description = "How many checks were done for the worker process the last time a spawn was tried.", currencyTimeLimit = 60)
-	public abstract int getLastStartupCheckCount();
-
-	@Nonnull
-	@Override
-	@ManagedAttribute(description = "The names of the current runs.", currencyTimeLimit = 5)
-	public final String[] getCurrentRunNames() {
-		List<String> names = runDB.listRunNames();
-		return names.toArray(new String[names.size()]);
-	}
-
-	@Override
-	@ManagedAttribute(description = "What the factory subprocess's main RMI interface is registered as.", currencyTimeLimit = 60)
-	public abstract String getFactoryProcessName();
-
-	/**
-	 * @return What was the exit code from the last time the factory subprocess
-	 *         was killed?
-	 */
-	@Override
-	@ManagedAttribute(description = "What was the exit code from the last time the factory subprocess was killed?")
-	public abstract Integer getLastExitCode();
-
-	/**
-	 * @return The mapping of user names to RMI factory IDs.
-	 */
-	@Override
-	@ManagedAttribute(description = "The mapping of user names to RMI factory IDs.", currencyTimeLimit = 60)
-	public abstract String[] getFactoryProcessMapping();
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
-	public final void setOperatingLimit(int operatingLimit) {
-		state.setOperatingLimit(operatingLimit);
-	}
-
-	@Override
-	@ManagedAttribute(description = "The maximum number of simultaneous operating runs supported by the server.", currencyTimeLimit = 300)
-	public final int getOperatingLimit() {
-		return state.getOperatingLimit();
-	}
-
-	/**
-	 * @return A count of the number of runs believed to actually be in the
-	 *         {@linkplain uk.org.taverna.server.master.common.Status#Operating
-	 *         operating} state.
-	 * @throws Exception
-	 *             If anything goes wrong.
-	 */
-	@Override
-	@ManagedMetric(description = "How many workflow runs are currently actually executing.", currencyTimeLimit = 10, metricType = GAUGE, category = "throughput")
-	public final int getOperatingCount() throws Exception {
-		return operatingCount();
-	}
-
-	@Override
-	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
-	public final void setGenerateProvenance(boolean genProv) {
-		state.setGenerateProvenance(genProv);
-	}
-
-	@Override
-	@ManagedAttribute(description="Whether to tell a workflow to generate provenance bundles by default.")
-	public final boolean getGenerateProvenance() {
-		return state.getGenerateProvenance();
-	}
-}


[13/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
new file mode 100644
index 0000000..e9b067e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerListenersREST.java
@@ -0,0 +1,428 @@
+/*
+ * 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.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/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
new file mode 100644
index 0000000..62158bb
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerREST.java
@@ -0,0 +1,604 @@
+/*
+ * 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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
new file mode 100644
index 0000000..2b328fd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerRunREST.java
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+import static javax.ws.rs.core.UriBuilder.fromUri;
+import static org.joda.time.format.ISODateTimeFormat.basicDateTime;
+import static org.taverna.server.master.common.Roles.USER;
+import static org.taverna.server.master.rest.handler.Scufl2DocumentHandler.SCUFL2;
+import static org.taverna.server.master.interaction.InteractionFeedSupport.FEED_URL_DIR;
+import static org.taverna.server.master.rest.ContentTypes.JSON;
+import static org.taverna.server.master.rest.ContentTypes.ROBUNDLE;
+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.TavernaServerRunREST.PathNames.DIR;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.GENERATE_PROVENANCE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.IN;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LISTEN;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.LOG;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.NAME;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.OUT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.PROFILE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.ROOT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.RUNBUNDLE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.SEC;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STATUS;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDERR;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.STDOUT;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_CREATE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_EXPIRE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_FINISH;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.T_START;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.USAGE;
+import static org.taverna.server.master.rest.TavernaServerRunREST.PathNames.WF;
+import static org.taverna.server.master.rest.handler.T2FlowDocumentHandler.T2FLOW;
+
+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.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+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.JAXBException;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.joda.time.format.DateTimeFormatter;
+import org.taverna.server.master.common.Namespaces;
+import org.taverna.server.master.common.ProfileList;
+import org.taverna.server.master.common.Status;
+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.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+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.interfaces.Listener;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * This represents how a Taverna Server workflow run looks to a RESTful API.
+ * 
+ * @author Donal Fellows.
+ */
+@Description("This represents how a Taverna Server workflow run looks to a "
+		+ "RESTful API.")
+@RolesAllowed(USER)
+public interface TavernaServerRunREST {
+	/**
+	 * Describes a workflow run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return The description.
+	 */
+	@GET
+	@Path(ROOT)
+	@Description("Describes a workflow run.")
+	@Produces({ XML, JSON })
+	@Nonnull
+	public RunDescription getDescription(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Deletes a workflow run.
+	 * 
+	 * @return An HTTP response to the deletion.
+	 * @throws NoUpdateException
+	 *             If the user may see the handle but may not delete it.
+	 */
+	@DELETE
+	@Path(ROOT)
+	@Description("Deletes a workflow run.")
+	@Nonnull
+	public Response destroy() throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ROOT)
+	@Description("Produces the description of the run.")
+	Response runOptions();
+
+	/**
+	 * Returns the workflow document used to create the workflow run.
+	 * 
+	 * @return The workflow document.
+	 */
+	@GET
+	@Path(WF)
+	@Produces({ T2FLOW, SCUFL2, XML, JSON })
+	@Description("Gives the workflow document used to create the workflow run.")
+	@Nonnull
+	public Workflow getWorkflow();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(WF)
+	@Description("Produces the description of the run workflow.")
+	Response workflowOptions();
+
+	/** Get the workflow name. */
+	@GET
+	@Path(NAME)
+	@Produces(TEXT)
+	@Description("Gives the descriptive name of the workflow run.")
+	@Nonnull
+	public String getName();
+
+	/**
+	 * Set the workflow name.
+	 * 
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to change the workflow.
+	 */
+	@PUT
+	@Path(NAME)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Set the descriptive name of the workflow run. Note that "
+			+ "this value may be arbitrarily truncated by the implementation.")
+	@Nonnull
+	public String setName(String name) throws NoUpdateException;
+
+	/** Produce the workflow name HTTP operations. */
+	@OPTIONS
+	@Path(NAME)
+	@Description("Produces the description of the operations on the run's "
+			+ "descriptive name.")
+	@Nonnull
+	Response nameOptions();
+
+	/**
+	 * Produces the name of the workflow's main profile.
+	 * 
+	 * @return The main profile name, or the empty string if there is no such
+	 *         profile.
+	 */
+	@GET
+	@Path(PROFILE)
+	@Produces(TEXT)
+	@Description("Gives the name of the workflow's main profile, or the empty string if none is defined.")
+	@Nonnull
+	String getMainProfileName();
+
+	/**
+	 * Get a description of the profiles supported by the workflow document used
+	 * to create this run.
+	 * 
+	 * @return A description of the supported profiles.
+	 */
+	@GET
+	@Path(PROFILE)
+	@Produces({ XML, JSON })
+	@Description("Describes what profiles exist on the workflow.")
+	@Nonnull
+	ProfileList getProfiles();
+
+	/** Produce the workflow profile HTTP operations. */
+	@OPTIONS
+	@Path(PROFILE)
+	@Description("Produces the description of the operations on the run's "
+			+ "profile.")
+	@Nonnull
+	Response profileOptions();
+
+	/**
+	 * Returns a resource that represents the workflow run's security
+	 * properties. These may only be accessed by the owner.
+	 * 
+	 * @return The security resource.
+	 * @throws NotOwnerException
+	 *             If the accessing principal isn't the owning principal.
+	 */
+	@Path(SEC)
+	@Description("Access the workflow run's security.")
+	@Nonnull
+	public TavernaServerSecurityREST getSecurity() throws NotOwnerException;
+
+	/**
+	 * Returns the time when the workflow run becomes eligible for automatic
+	 * deletion.
+	 * 
+	 * @return When the run expires.
+	 */
+	@GET
+	@Path(T_EXPIRE)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run becomes eligible for "
+			+ "automatic deletion.")
+	@Nonnull
+	public String getExpiryTime();
+
+	/**
+	 * Sets the time when the workflow run becomes eligible for automatic
+	 * deletion.
+	 * 
+	 * @param expiry
+	 *            When the run will expire.
+	 * @return When the run will actually expire.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to manage the lifetime
+	 *             of the run.
+	 */
+	@PUT
+	@Path(T_EXPIRE)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Sets the time when the workflow run becomes eligible for "
+			+ "automatic deletion.")
+	@Nonnull
+	public String setExpiryTime(@Nonnull String expiry)
+			throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_EXPIRE)
+	@Description("Produces the description of the run expiry.")
+	Response expiryOptions();
+
+	/**
+	 * Returns the time when the workflow run was created.
+	 * 
+	 * @return When the run was first submitted to the server.
+	 */
+	@GET
+	@Path(T_CREATE)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was first submitted "
+			+ "to the server.")
+	@Nonnull
+	public String getCreateTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_CREATE)
+	@Description("Produces the description of the run create time.")
+	Response createTimeOptions();
+
+	/**
+	 * Returns the time when the workflow run was started (through a user-driven
+	 * state change).
+	 * 
+	 * @return When the run was started, or <tt>null</tt>.
+	 */
+	@GET
+	@Path(T_START)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was started, or an "
+			+ "empty string if the run has not yet started.")
+	@Nonnull
+	public String getStartTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_START)
+	@Description("Produces the description of the run start time.")
+	Response startTimeOptions();
+
+	/**
+	 * Returns the time when the workflow run was detected to have finished.
+	 * 
+	 * @return When the run finished, or <tt>null</tt>.
+	 */
+	@GET
+	@Path(T_FINISH)
+	@Produces(TEXT)
+	@Description("Gives the time when the workflow run was first detected as "
+			+ "finished, or an empty string if it has not yet finished "
+			+ "(including if it has never started).")
+	@Nonnull
+	public String getFinishTime();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(T_FINISH)
+	@Description("Produces the description of the run finish time.")
+	Response finishTimeOptions();
+
+	/**
+	 * Gets the current status of the workflow run.
+	 * 
+	 * @return The status code.
+	 */
+	@GET
+	@Path(STATUS)
+	@Produces(TEXT)
+	@Description("Gives the current status of the workflow run.")
+	@Nonnull
+	public String getStatus();
+
+	/**
+	 * Sets the status of the workflow run. This does nothing if the status code
+	 * is the same as the run's current state.
+	 * 
+	 * @param status
+	 *            The new status code.
+	 * @return Description of what status the run is actually in, or a 202 to
+	 *         indicate that things are still changing.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to update the run.
+	 * @throws BadStateChangeException
+	 *             If the state cannot be modified in the manner requested.
+	 */
+	@PUT
+	@Path(STATUS)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Attempts to update the status of the workflow run.")
+	@Nonnull
+	public Response setStatus(@Nonnull String status) throws NoUpdateException,
+			BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STATUS)
+	@Description("Produces the description of the run status.")
+	Response statusOptions();
+
+	/**
+	 * Get the working directory of this workflow run.
+	 * 
+	 * @return A RESTful delegate for the working directory.
+	 */
+	@Path(DIR)
+	@Description("Get the working directory of this workflow run.")
+	@Nonnull
+	public TavernaServerDirectoryREST getWorkingDirectory();
+
+	/**
+	 * Get the event listeners attached to this workflow run.
+	 * 
+	 * @return A RESTful delegate for the list of listeners.
+	 */
+	@Path(LISTEN)
+	@Description("Get the event listeners attached to this workflow run.")
+	@Nonnull
+	public TavernaServerListenersREST getListeners();
+
+	/**
+	 * Get a delegate for working with the inputs to this workflow run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return A RESTful delegate for the inputs.
+	 */
+	@Path(IN)
+	@Description("Get the inputs to this workflow run.")
+	@Nonnull
+	public TavernaServerInputREST getInputs(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Get the output Baclava file for this workflow run.
+	 * 
+	 * @return The filename, or empty string to indicate that the outputs will
+	 *         be written to the <tt>out</tt> directory.
+	 */
+	@GET
+	@Path(OUT)
+	@Produces(TEXT)
+	@Description("Gives the Baclava file where output will be written; empty "
+			+ "means use multiple simple files in the out directory.")
+	@Nonnull
+	public String getOutputFile();
+
+	/**
+	 * Get a description of the outputs.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this operation.
+	 * @return A description of the outputs (higher level than the filesystem).
+	 * @throws BadStateChangeException
+	 *             If the run is in the {@link Status#Initialized Initialized}
+	 *             state.
+	 * @throws FilesystemAccessException
+	 *             If problems occur when accessing the filesystem.
+	 * @throws NoDirectoryEntryException
+	 *             If things are odd in the filesystem.
+	 */
+	@GET
+	@Path(OUT)
+	@Produces({ XML, JSON })
+	@Description("Gives a description of the outputs, as currently understood")
+	@Nonnull
+	public OutputDescription getOutputDescription(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Set the output Baclava file for this workflow run.
+	 * 
+	 * @param filename
+	 *            The Baclava file to use, or empty to make the outputs be
+	 *            written to individual files in the <tt>out</tt> subdirectory
+	 *            of the working directory.
+	 * @return The Baclava file as actually set.
+	 * @throws NoUpdateException
+	 *             If the current user is not permitted to update the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is invalid (starts with <tt>/</tt> or
+	 *             contains a <tt>..</tt> segment).
+	 * @throws BadStateChangeException
+	 *             If the workflow is not in the Initialized state.
+	 */
+	@PUT
+	@Path(OUT)
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Description("Sets the Baclava file where output will be written; empty "
+			+ "means use multiple simple files in the out directory.")
+	@Nonnull
+	public String setOutputFile(@Nonnull String filename)
+			throws NoUpdateException, FilesystemAccessException,
+			BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(OUT)
+	@Description("Produces the description of the run output.")
+	Response outputOptions();
+
+	/**
+	 * Get a handle to the interaction feed.
+	 * 
+	 * @return
+	 */
+	@Path(FEED_URL_DIR)
+	@Description("Access the interaction feed for the workflow run.")
+	@Nonnull
+	InteractionFeedREST getInteractionFeed();
+
+	/**
+	 * @return The stdout for the workflow run, or empty string if the run has
+	 *         not yet started.
+	 * @throws NoListenerException
+	 */
+	@GET
+	@Path(STDOUT)
+	@Description("Return the stdout for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	String getStdout() throws NoListenerException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STDOUT)
+	@Description("Return the stdout for the workflow run.")
+	Response stdoutOptions();
+
+	/**
+	 * @return The stderr for the workflow run, or empty string if the run has
+	 *         not yet started.
+	 * @throws NoListenerException
+	 */
+	@GET
+	@Path(STDERR)
+	@Description("Return the stderr for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	String getStderr() throws NoListenerException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(STDERR)
+	@Description("Return the stderr for the workflow run.")
+	Response stderrOptions();
+
+	/**
+	 * @return The usage record for the workflow run, wrapped in a Response, or
+	 *         "empty content" if the run has not yet finished.
+	 * @throws NoListenerException
+	 * @throws JAXBException
+	 */
+	@GET
+	@Path(USAGE)
+	@Description("Return the usage record for the workflow run.")
+	@Produces(XML)
+	@Nonnull
+	Response getUsage() throws NoListenerException, JAXBException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(USAGE)
+	@Description("Return the usage record for the workflow run.")
+	Response usageOptions();
+
+	/**
+	 * @return The log for the workflow run, or empty string if the run has not
+	 *         yet started.
+	 */
+	@GET
+	@Path(LOG)
+	@Description("Return the log for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	Response getLogContents();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(LOG)
+	@Description("Return the log for the workflow run.")
+	Response logOptions();
+
+	/**
+	 * @return The log for the workflow run, or empty string if the run has not
+	 *         yet started.
+	 */
+	@GET
+	@Path(RUNBUNDLE)
+	@Description("Return the run bundle for the workflow run.")
+	@Produces(ROBUNDLE)
+	@Nonnull
+	Response getRunBundle();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(RUNBUNDLE)
+	@Description("Return the run bundle for the workflow run.")
+	Response runBundleOptions();
+
+	/**
+	 * @return Whether to create the run bundle for the workflow run. Only
+	 *         usefully set-able before the start of the run.
+	 */
+	@GET
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	@Produces(TEXT)
+	@Nonnull
+	boolean getGenerateProvenance();
+
+	/**
+	 * @param provenanceFlag
+	 *            Whether to create the run bundle for the workflow run. Only
+	 *            usefully set-able before the start of the run.
+	 * @return What it was actually set to.
+	 * @throws NoUpdateException 
+	 */
+	@PUT
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Nonnull
+	boolean setGenerateProvenance(boolean provenanceFlag) throws NoUpdateException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(GENERATE_PROVENANCE)
+	@Description("Whether to create the run bundle for the workflow run.")
+	Response generateProvenanceOptions();
+
+	/**
+	 * Factored out path names used in the {@link TavernaServerRunREST}
+	 * interface and related places.
+	 * 
+	 * @author Donal Fellows
+	 */
+	interface PathNames {
+		public static final String ROOT = "/";
+		public static final String WF = "workflow";
+		public static final String DIR = "wd";
+		public static final String NAME = "name";
+		public static final String T_EXPIRE = "expiry";
+		public static final String T_CREATE = "createTime";
+		public static final String T_START = "startTime";
+		public static final String T_FINISH = "finishTime";
+		public static final String STATUS = "status";
+		public static final String IN = "input";
+		public static final String OUT = "output";
+		public static final String PROFILE = "profile";
+		public static final String LISTEN = "listeners";
+		public static final String SEC = "security";
+		public static final String STDOUT = "stdout";
+		public static final String STDERR = "stderr";
+		public static final String USAGE = "usage";
+		public static final String LOG = "log";
+		public static final String RUNBUNDLE = "run-bundle";
+		public static final String GENERATE_PROVENANCE = "generate-provenance";
+	}
+
+	/**
+	 * The description of where everything is in a RESTful view of a workflow
+	 * run. Done with JAXB.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement
+	@XmlType(name = "")
+	public static class RunDescription extends VersionedElement {
+		/** The identity of the owner of the workflow run. */
+		@XmlAttribute(namespace = Namespaces.SERVER_REST)
+		public String owner;
+		/** The description of the expiry. */
+		public Expiry expiry;
+		/** The location of the creation workflow description. */
+		public Uri creationWorkflow;
+		/** The location of the creation time property. */
+		public Uri createTime;
+		/** The location of the start time property. */
+		public Uri startTime;
+		/** The location of the finish time property. */
+		public Uri finishTime;
+		/** The location of the status description. */
+		public Uri status;
+		/** The location of the working directory. */
+		public Uri workingDirectory;
+		/** The location of the inputs. */
+		public Uri inputs;
+		/** The location of the Baclava output. */
+		public Uri output;
+		/** The location of the security context. */
+		public Uri securityContext;
+		/** The list of listeners. */
+		public ListenerList listeners;
+		/** The location of the interaction feed. */
+		public Uri interaction;
+		/** The name of the run. */
+		public Uri name;
+		/** The stdout of the run. */
+		public Uri stdout;
+		/** The stderr of the run. */
+		public Uri stderr;
+		/** The usage record for the run. */
+		public Uri usage;
+		/** The log from the run. */
+		public Uri log;
+		/** The bundle describing the run. */
+		@XmlElement(name = RUNBUNDLE)
+		public Uri runBundle;
+		/** Whether to generate a bundle describing the run. */
+		@XmlElement(name = GENERATE_PROVENANCE)
+		public Uri generateProvenance;
+
+		/**
+		 * How to describe a run's expiry.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class Expiry {
+			/**
+			 * Where to go to read the exiry
+			 */
+			@XmlAttribute(name = "href", namespace = Namespaces.XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI ref;
+			/**
+			 * What the expiry currently is.
+			 */
+			@XmlValue
+			public String timeOfDeath;
+
+			/**
+			 * Make a blank expiry description.
+			 */
+			public Expiry() {
+			}
+
+			private static DateTimeFormatter dtf;
+
+			Expiry(TavernaRun r, UriInfo ui, String path, String... parts) {
+				ref = fromUri(new Uri(ui, true, path, parts).ref).build();
+				if (dtf == null)
+					dtf = basicDateTime();
+				timeOfDeath = dtf.print(r.getExpiry().getTime());
+			}
+		}
+
+		/**
+		 * The description of a list of listeners attached to a run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "")
+		public static class ListenerList extends Uri {
+			/**
+			 * The references to the individual listeners.
+			 */
+			public List<Uri> listener;
+
+			/**
+			 * An empty description of listeners.
+			 */
+			public ListenerList() {
+				listener = new ArrayList<>();
+			}
+
+			/**
+			 * @param r
+			 *            The run whose listeners we're talking about.
+			 * @param ub
+			 *            Uri factory; must've been secured
+			 */
+			private ListenerList(TavernaRun r, UriBuilder ub) {
+				super(ub);
+				listener = new ArrayList<>(r.getListeners().size());
+				UriBuilder pathUB = ub.clone().path("{name}");
+				for (Listener l : r.getListeners())
+					listener.add(new Uri(pathUB.build(l.getName())));
+			}
+
+			/**
+			 * @param run
+			 *            The run whose listeners we're talking about.
+			 * @param ui
+			 *            The source of information about URIs.
+			 * @param path
+			 *            Where we are relative to the URI source.
+			 * @param parts
+			 *            Anything required to fill out the path.
+			 */
+			ListenerList(TavernaRun run, UriInfo ui, String path,
+					String... parts) {
+				this(run, secure(fromUri(new Uri(ui, path, parts).ref)));
+			}
+		}
+
+		/**
+		 * An empty description of a run.
+		 */
+		public RunDescription() {
+		}
+
+		/**
+		 * A description of a particular run.
+		 * 
+		 * @param run
+		 *            The run to describe.
+		 * @param ui
+		 *            The factory for URIs.
+		 */
+		public RunDescription(TavernaRun run, UriInfo ui) {
+			super(true);
+			creationWorkflow = new Uri(ui, WF);
+			expiry = new Expiry(run, ui, T_EXPIRE);
+			status = new Uri(ui, STATUS);
+			workingDirectory = new Uri(ui, DIR);
+			listeners = new ListenerList(run, ui, LISTEN);
+			securityContext = new Uri(ui, SEC);
+			inputs = new Uri(ui, IN);
+			output = new Uri(ui, OUT);
+			createTime = new Uri(ui, T_CREATE);
+			startTime = new Uri(ui, T_START);
+			finishTime = new Uri(ui, T_FINISH);
+			interaction = new Uri(ui, FEED_URL_DIR);
+			name = new Uri(ui, NAME);
+			owner = run.getSecurityContext().getOwner().getName();
+			stdout = new Uri(ui, STDOUT);
+			stderr = new Uri(ui, STDERR);
+			usage = new Uri(ui, USAGE);
+			log = new Uri(ui, LOG);
+			runBundle = new Uri(ui, RUNBUNDLE);
+			generateProvenance = new Uri(ui, GENERATE_PROVENANCE);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
new file mode 100644
index 0000000..73000e8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/TavernaServerSecurityREST.java
@@ -0,0 +1,775 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest;
+
+import static java.util.Collections.emptyList;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+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 static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.CREDS;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_CRED;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_PERM;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ONE_TRUST;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.OWNER;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.PERMS;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.ROOT;
+import static org.taverna.server.master.rest.TavernaServerSecurityREST.PathNames.TRUSTS;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+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.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.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.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.taverna.server.master.common.Credential;
+import org.taverna.server.master.common.Permission;
+import org.taverna.server.master.common.Trust;
+import org.taverna.server.master.common.Uri;
+import org.taverna.server.master.common.VersionedElement;
+import org.taverna.server.master.exceptions.BadStateChangeException;
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+import org.taverna.server.master.exceptions.NoCredentialException;
+
+/**
+ * Manages the security of the workflow run. In general, only the owner of a run
+ * may access this resource. Many of these security-related resources may only
+ * be changed before the run is set to operating.
+ * 
+ * @author Donal Fellows
+ */
+@RolesAllowed(USER)
+@Description("Manages the security of the workflow run. In general, only the "
+		+ "owner of a run may access this resource.")
+public interface TavernaServerSecurityREST {
+	interface PathNames {
+		final String ROOT = "/";
+		final String OWNER = "owner";
+		final String CREDS = "credentials";
+		final String ONE_CRED = CREDS + "/{id}";
+		final String TRUSTS = "trusts";
+		final String ONE_TRUST = TRUSTS + "/{id}";
+		final String PERMS = "permissions";
+		final String ONE_PERM = PERMS + "/{id}";
+	}
+
+	/**
+	 * Gets a description of the security information supported by the workflow
+	 * run.
+	 * 
+	 * @param ui
+	 *            About the URI used to access this resource.
+	 * @return A description of the security information.
+	 */
+	@GET
+	@Path(ROOT)
+	@Produces({ XML, JSON })
+	@Description("Gives a description of the security information supported "
+			+ "by the workflow run.")
+	@Nonnull
+	Descriptor describe(@Nonnull @Context UriInfo ui);
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ROOT)
+	@Description("Produces the description of the run security.")
+	Response descriptionOptions();
+
+	/**
+	 * Gets the identity of who owns the workflow run.
+	 * 
+	 * @return The name of the owner of the run.
+	 */
+	@GET
+	@Path(OWNER)
+	@Produces(TEXT)
+	@Description("Gives the identity of who owns the workflow run.")
+	@Nonnull
+	String getOwner();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(OWNER)
+	@Description("Produces the description of the run owner.")
+	Response ownerOptions();
+
+	/*
+	 * @PUT @Path("/") @Consumes(ContentTypes.BYTES) @CallCounted @Nonnull
+	 * public void set(@Nonnull InputStream contents, @Nonnull @Context UriInfo
+	 * ui);
+	 */
+
+	/**
+	 * @return A list of credentials supplied to this workflow run.
+	 */
+	@GET
+	@Path(CREDS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of credentials supplied to this workflow run.")
+	@Nonnull
+	CredentialList listCredentials();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(CREDS)
+	@Description("Produces the description of the run credentials' operations.")
+	Response credentialsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_CRED)
+	@Description("Produces the description of one run credential's operations.")
+	Response credentialOptions(@PathParam("id") String id);
+
+	/**
+	 * Describe a particular credential.
+	 * 
+	 * @param id
+	 *            The id of the credential to fetch.
+	 * @return The description of the credential.
+	 * @throws NoCredentialException
+	 *             If the credential doesn't exist.
+	 */
+	@GET
+	@Path(ONE_CRED)
+	@Produces({ XML, JSON })
+	@Description("Describes a particular credential.")
+	@Nonnull
+	CredentialHolder getParticularCredential(@Nonnull @PathParam("id") String id)
+			throws NoCredentialException;
+
+	/**
+	 * Update a particular credential.
+	 * 
+	 * @param id
+	 *            The id of the credential to update.
+	 * @param c
+	 *            The details of the credential to use in the update.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the updated credential.
+	 * @throws InvalidCredentialException
+	 *             If the credential description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@PUT
+	@Path(ONE_CRED)
+	@Consumes({ XML, JSON })
+	@Produces({ XML, JSON })
+	@Description("Updates a particular credential.")
+	@Nonnull
+	CredentialHolder setParticularCredential(
+			@Nonnull @PathParam("id") String id, @Nonnull CredentialHolder c,
+			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Adds a new credential.
+	 * 
+	 * @param c
+	 *            The details of the credential to create.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the created credential.
+	 * @throws InvalidCredentialException
+	 *             If the credential description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@POST
+	@Path(CREDS)
+	@Consumes({ XML, JSON })
+	@Description("Creates a new credential.")
+	@Nonnull
+	Response addCredential(@Nonnull CredentialHolder c,
+			@Nonnull @Context UriInfo ui) throws InvalidCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Deletes all credentials associated with a run.
+	 * 
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(CREDS)
+	@Description("Deletes all credentials.")
+	@Nonnull
+	Response deleteAllCredentials(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException;
+
+	/**
+	 * Deletes one credential associated with a run.
+	 * 
+	 * @param id
+	 *            The identity of the credential to delete.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(ONE_CRED)
+	@Description("Deletes a particular credential.")
+	@Nonnull
+	Response deleteCredential(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(TRUSTS)
+	@Description("Produces the description of the run trusted certificates' "
+			+ "operations.")
+	Response trustsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_TRUST)
+	@Description("Produces the description of one run trusted certificate's "
+			+ "operations.")
+	Response trustOptions(@PathParam("id") String id);
+
+	/**
+	 * @return A list of trusted identities supplied to this workflow run.
+	 */
+	@GET
+	@Path(TRUSTS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of trusted identities supplied to this "
+			+ "workflow run.")
+	@Nonnull
+	TrustList listTrusted();
+
+	/**
+	 * Describe a particular trusted identity.
+	 * 
+	 * @param id
+	 *            The id of the trusted identity to fetch.
+	 * @return The description of the trusted identity.
+	 * @throws NoCredentialException
+	 *             If the trusted identity doesn't exist.
+	 */
+	@GET
+	@Path(ONE_TRUST)
+	@Produces({ XML, JSON })
+	@Description("Describes a particular trusted identity.")
+	@Nonnull
+	Trust getParticularTrust(@Nonnull @PathParam("id") String id)
+			throws NoCredentialException;
+
+	/**
+	 * Update a particular trusted identity.
+	 * 
+	 * @param id
+	 *            The id of the trusted identity to update.
+	 * @param t
+	 *            The details of the trusted identity to use in the update.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the updated trusted identity.
+	 * @throws InvalidCredentialException
+	 *             If the trusted identity description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@PUT
+	@Path(ONE_TRUST)
+	@Consumes({ XML, JSON })
+	@Produces({ XML, JSON })
+	@Description("Updates a particular trusted identity.")
+	@Nonnull
+	Trust setParticularTrust(@Nonnull @PathParam("id") String id,
+			@Nonnull Trust t, @Nonnull @Context UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException;
+
+	/**
+	 * Adds a new trusted identity.
+	 * 
+	 * @param t
+	 *            The details of the trusted identity to create.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return Description of the created trusted identity.
+	 * @throws InvalidCredentialException
+	 *             If the trusted identity description isn't valid.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@POST
+	@Path(TRUSTS)
+	@Consumes({ XML, JSON })
+	@Description("Adds a new trusted identity.")
+	@Nonnull
+	Response addTrust(@Nonnull Trust t, @Nonnull @Context UriInfo ui)
+			throws InvalidCredentialException, BadStateChangeException;
+
+	/**
+	 * Deletes all trusted identities associated with a run.
+	 * 
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(TRUSTS)
+	@Description("Deletes all trusted identities.")
+	@Nonnull
+	Response deleteAllTrusts(@Nonnull @Context UriInfo ui)
+			throws BadStateChangeException;
+
+	/**
+	 * Deletes one trusted identity associated with a run.
+	 * 
+	 * @param id
+	 *            The identity of the trusted identity to delete.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return A characterisation of a successful delete.
+	 * @throws BadStateChangeException
+	 *             If the workflow run is not in the initialising state.
+	 */
+	@DELETE
+	@Path(ONE_TRUST)
+	@Description("Deletes a particular trusted identity.")
+	@Nonnull
+	Response deleteTrust(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui) throws BadStateChangeException;
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(PERMS)
+	@Description("Produces the description of the run permissions' operations.")
+	Response permissionsOptions();
+
+	/** Get an outline of the operations supported. */
+	@OPTIONS
+	@Path(ONE_PERM)
+	@Description("Produces the description of one run permission's operations.")
+	Response permissionOptions(@PathParam("id") String id);
+
+	/**
+	 * @return A list of (non-default) permissions associated with this workflow
+	 *         run.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 */
+	@GET
+	@Path(PERMS)
+	@Produces({ XML, JSON })
+	@Description("Gives a list of all non-default permissions associated with "
+			+ "the enclosing workflow run. By default, nobody has any access "
+			+ "at all except for the owner of the run.")
+	@Nonnull
+	PermissionsDescription describePermissions(@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Describe the particular permission granted to a user.
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be described.
+	 * @return The permission they are granted.
+	 */
+	@GET
+	@Path(ONE_PERM)
+	@Produces(TEXT)
+	@Description("Describes the permission granted to a particular user.")
+	@Nonnull
+	Permission describePermission(@Nonnull @PathParam("id") String id);
+
+	/**
+	 * Update the permission granted to a user.
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be updated. Note
+	 *            that the owner always has full permissions.
+	 * @param perm
+	 *            The permission level to set.
+	 * @return The permission level that has actually been set.
+	 */
+	@PUT
+	@Consumes(TEXT)
+	@Produces(TEXT)
+	@Path(ONE_PERM)
+	@Description("Updates the permissions granted to a particular user.")
+	@Nonnull
+	Permission setPermission(@Nonnull @PathParam("id") String id,
+			@Nonnull Permission perm);
+
+	/**
+	 * Delete the permissions associated with a user, which restores them to the
+	 * default (no access unless they are the owner or have admin privileges).
+	 * 
+	 * @param id
+	 *            The name of the user whose permissions are to be revoked.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return An indication that the delete has been successful (or not).
+	 */
+	@DELETE
+	@Path(ONE_PERM)
+	@Description("Deletes (by resetting to default) the permissions "
+			+ "associated with a particular user.")
+	@Nonnull
+	Response deletePermission(@Nonnull @PathParam("id") String id,
+			@Nonnull @Context UriInfo ui);
+
+	/**
+	 * Manufacture a permission setting for a previously-unknown user.
+	 * 
+	 * @param desc
+	 *            A description of the name of the user and the permission level
+	 *            to grant them.
+	 * @param ui
+	 *            Information about the URI used to access this resource.
+	 * @return An indication that the create has been successful (or not).
+	 */
+	@POST
+	@Path(PERMS)
+	@Consumes({ XML, JSON })
+	@Description("Creates a new assignment of permissions to a particular user.")
+	@Nonnull
+	Response makePermission(@Nonnull PermissionDescription desc,
+			@Nonnull @Context UriInfo ui);
+
+	/**
+	 * A description of the security resources associated with a workflow run.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "securityDescriptor")
+	@XmlType(name = "SecurityDescriptor")
+	public static final class Descriptor extends VersionedElement {
+		/** The identity of the owner of the enclosing workflow run. */
+		@XmlElement
+		public String owner;
+		/** Where to get the permissions on the run. */
+		@XmlElement
+		public Uri permissions;
+
+		/** Characterisation of the credentials attached to the run. */
+		@XmlElement
+		public Credentials credentials;
+		/** Characterisation of the trusted certificates attached to the run. */
+		@XmlElement
+		public Trusts trusts;
+
+		public Descriptor() {
+		}
+
+		/**
+		 * Initialise a description of the security context.
+		 * 
+		 * @param ub
+		 *            How to build URIs.
+		 * @param owner
+		 *            Who owns the context.
+		 * @param credential
+		 *            The credentials associated with the context.
+		 * @param trust
+		 *            The trusted certificates associated with the context.
+		 */
+		public Descriptor(@Nonnull UriBuilder ub, @Nonnull String owner,
+				@Nonnull Credential[] credential, @Nonnull Trust[] trust) {
+			super(true);
+			this.owner = owner;
+			this.permissions = new Uri(ub, PERMS);
+			this.credentials = new Credentials(new Uri(ub, CREDS).ref,
+					credential);
+			this.trusts = new Trusts(new Uri(ub, TRUSTS).ref, trust);
+		}
+
+		/**
+		 * A description of credentials associated with a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "CredentialCollection")
+		public static final class Credentials {
+			/** Reference to the collection of credentials */
+			@XmlAttribute(name = "href", namespace = XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI href;
+			/** Descriptions of the credentials themselves. */
+			@XmlElement
+			public List<CredentialHolder> credential = new ArrayList<>();
+
+			public Credentials() {
+			}
+
+			/**
+			 * Initialise a description of the credentials.
+			 * 
+			 * @param uri
+			 *            the URI of the collection.
+			 * @param credential
+			 *            The credentials in the collection.
+			 */
+			public Credentials(@Nonnull URI uri,
+					@Nonnull Credential[] credential) {
+				this.href = uri;
+				for (Credential c : credential)
+					this.credential.add(new CredentialHolder(c));
+			}
+		}
+
+		/**
+		 * A description of trusted certificates associated with a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlType(name = "TrustCollection")
+		public static final class Trusts {
+			/** Reference to the collection of trusted certs */
+			@XmlAttribute(name = "href", namespace = XLINK)
+			@XmlSchemaType(name = "anyURI")
+			public URI href;
+			/** Descriptions of the trusted certs themselves. */
+			@XmlElement
+			public Trust[] trust;
+
+			public Trusts() {
+			}
+
+			/**
+			 * Initialise a description of the trusted certificates.
+			 * 
+			 * @param uri
+			 *            the URI of the collection.
+			 * @param trust
+			 *            The trusted certificates in the collection.
+			 */
+			public Trusts(@Nonnull URI uri, @Nonnull Trust[] trust) {
+				this.href = uri;
+				this.trust = trust.clone();
+			}
+		}
+	}
+
+	/**
+	 * A container for a credential, used to work around issues with type
+	 * inference in CXF's REST service handling and JAXB.
+	 * 
+	 * @see Credential.KeyPair
+	 * @see Credential.Password
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "credential")
+	@XmlType(name = "Credential")
+	public static final class CredentialHolder {
+		/**
+		 * The credential inside this holder.
+		 */
+		@XmlElements({
+				@XmlElement(name = "keypair", namespace = SERVER, type = Credential.KeyPair.class, required = true),
+				@XmlElement(name = "userpass", namespace = SERVER, type = Credential.Password.class, required = true) })
+		public Credential credential;
+
+		public CredentialHolder() {
+		}
+
+		public CredentialHolder(Credential credential) {
+			this.credential = credential;
+		}
+
+		/**
+		 * Convenience accessor function.
+		 * 
+		 * @return The keypair credential held in this holder.
+		 */
+		@XmlTransient
+		public Credential.KeyPair getKeypair() {
+			return (Credential.KeyPair) this.credential;
+		}
+
+		/**
+		 * Convenience accessor function.
+		 * 
+		 * @return The userpass credential held in this holder.
+		 */
+		@XmlTransient
+		public Credential.Password getUserpass() {
+			return (Credential.Password) this.credential;
+		}
+	}
+
+	/**
+	 * A simple list of credential descriptions.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "credentials")
+	public static final class CredentialList extends VersionedElement {
+		/** The descriptions of the credentials */
+		@XmlElement
+		@Nonnull
+		public List<CredentialHolder> credential = new ArrayList<>();
+
+		public CredentialList() {
+		}
+
+		/**
+		 * Initialise the list of credentials.
+		 * 
+		 * @param credential
+		 *            The descriptions of individual credentials.
+		 */
+		public CredentialList(@Nonnull Credential[] credential) {
+			super(true);
+			for (Credential c : credential)
+				this.credential.add(new CredentialHolder(c));
+		}
+	}
+
+	/**
+	 * A simple list of trusted certificate descriptions.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "trustedIdentities")
+	public static final class TrustList extends VersionedElement {
+		/** The descriptions of the trusted certificates */
+		@XmlElement
+		public Trust[] trust;
+
+		public TrustList() {
+		}
+
+		/**
+		 * Initialise the list of trusted certificates.
+		 * 
+		 * @param trust
+		 *            The descriptions of individual certificates.
+		 */
+		public TrustList(@Nonnull Trust[] trust) {
+			super(true);
+			this.trust = trust.clone();
+		}
+	}
+
+	/**
+	 * A description of the permissions granted to others by the owner of a
+	 * workflow run.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "permissionsDescriptor")
+	public static class PermissionsDescription extends VersionedElement {
+		/**
+		 * A description of the permissions granted to one user by the owner of
+		 * a workflow run.
+		 * 
+		 * @author Donal Fellows
+		 */
+		@XmlRootElement(name = "userPermission")
+		public static class LinkedPermissionDescription extends Uri {
+			/** Who is this granted to? */
+			@XmlElement
+			public String userName;
+			/** What are they granted? */
+			@XmlElement
+			public Permission permission;
+
+			public LinkedPermissionDescription() {
+			}
+
+			/**
+			 * Initialise a description of one user's permissions.
+			 * 
+			 * @param ub
+			 *            How to build the URI to this permission. Already
+			 *            secured.
+			 * @param userName
+			 *            Who this relates to.
+			 * @param permission
+			 *            What permission is granted.
+			 * @param strings
+			 *            Parameters to the URI builder.
+			 */
+			LinkedPermissionDescription(@Nonnull UriBuilder ub,
+					@Nonnull String userName, @Nonnull Permission permission,
+					String... strings) {
+				super(ub, strings);
+				this.userName = userName;
+				this.permission = permission;
+			}
+		}
+
+		/** List of descriptions of permissions. */
+		@XmlElement
+		public List<LinkedPermissionDescription> permission;
+
+		public PermissionsDescription() {
+			permission = emptyList();
+		}
+
+		/**
+		 * Initialise the description of a collection of permissions.
+		 * 
+		 * @param ub
+		 *            How to build URIs to this collection. Must have already
+		 *            been secured.
+		 * @param permissionMap
+		 *            The permissions to describe.
+		 */
+		public PermissionsDescription(@Nonnull UriBuilder ub,
+				@Nonnull Map<String, Permission> permissionMap) {
+			permission = new ArrayList<>();
+			List<String> userNames = new ArrayList<>(permissionMap.keySet());
+			Collections.sort(userNames);
+			for (String user : userNames)
+				permission.add(new LinkedPermissionDescription(ub, user,
+						permissionMap.get(user), user));
+		}
+	}
+
+	/**
+	 * An instruction to update the permissions for a user.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlRootElement(name = "permissionUpdate")
+	public static class PermissionDescription {
+		/** Who to set the permission for? */
+		@XmlElement
+		public String userName;
+		/** What permission to grant them? */
+		@XmlElement
+		public Permission permission;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
new file mode 100644
index 0000000..8b9c75f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/AccessDeniedHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.springframework.security.access.AccessDeniedException;
+
+public class AccessDeniedHandler extends HandlerCore implements
+		ExceptionMapper<AccessDeniedException> {
+	@Override
+	public Response toResponse(AccessDeniedException exception) {
+		return respond(FORBIDDEN, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
new file mode 100644
index 0000000..254382b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadInputPortNameHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadInputPortNameException;
+
+@Provider
+public class BadInputPortNameHandler extends HandlerCore implements
+		ExceptionMapper<BadInputPortNameException> {
+	@Override
+	public Response toResponse(BadInputPortNameException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
new file mode 100644
index 0000000..6ded568
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadPropertyValueHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadPropertyValueException;
+
+@Provider
+public class BadPropertyValueHandler extends HandlerCore implements
+		ExceptionMapper<BadPropertyValueException> {
+	@Override
+	public Response toResponse(BadPropertyValueException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
new file mode 100644
index 0000000..9501923
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/BadStateChangeHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.BadStateChangeException;
+
+@Provider
+public class BadStateChangeHandler extends HandlerCore implements
+		ExceptionMapper<BadStateChangeException> {
+	@Override
+	public Response toResponse(BadStateChangeException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file


[06/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/resources/static/jquery-1.8.0.min.js
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/resources/static/jquery-1.8.0.min.js b/taverna-server-webapp/src/main/resources/static/jquery-1.8.0.min.js
new file mode 100644
index 0000000..f121291
--- /dev/null
+++ b/taverna-server-webapp/src/main/resources/static/jquery-1.8.0.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v@1.8.0 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(
 a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="scri
 pt"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bX(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bV.length;while(e--){b=bV[e]+c;if(b in a)return b}return d}function bY(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function bZ(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bY(c)&&(e[f]=p._data(c,"olddisplay",cb(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b$(a,b,c){
 var d=bO.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function b_(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bU[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bU[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bU[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bU[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bU[e]+"Width"))||0));return f}function ca(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bP.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+b_(a,b,c||(f?"border":"content"),e)+"px"}function cb(a){if(bR[a])return bR[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createEle
 ment)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bR[a]=c,c}function ch(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||cd.test(a)?d(a,e):ch(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ch(a+"["+e+"]",b[e],c,d);else d(a,b)}function cy(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cz(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cu;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cz(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cz(a,c,d,e,"*",g)),h}function cA(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c
 )c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cB(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cC(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"succe
 ss",data:b}}function cK(){try{return new a.XMLHttpRequest}catch(b){}}function cL(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cT(){return setTimeout(function(){cM=b},0),cM=p.now()}function cU(a,b){p.each(b,function(b,c){var d=(cS[b]||[]).concat(cS["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cV(a,b,c){var d,e=0,f=0,g=cR.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cM||cT(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cM||cT(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.t
 weens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cW(k,j.opts.specialEasing);for(;e<g;e++){d=cR[e].call(j,a,k,j.opts);if(d)return d}return cU(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cW(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cX(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bY(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||
 "width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cb(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cO.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cY(a,b,c,d,e){return new cY.prototype.init(a,b,c,d,e)}function cZ(a,b){var c,d={height:a},e=0;for(;e<4;e+=2-b)c=bU[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d
 .width=a),d}function c_(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=r.test(" ")?/^[\s\xA0]+|[\s\xA0]+$/g:/^\s+|\s+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:fu
 nction(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.0",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return
  d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)contin
 ue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.p
 rototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("In
 valid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":a.toString().replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:functi
 on(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||f.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if
 (c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete"||e.readyState!=="loading"&&e.addEventListener)setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;
 h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){p.isFunction(c)&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callba
 cks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return typeof a=="object"?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.n
 otifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length||!d)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkO
 n:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).c
 loneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display
 :block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/^(?:\{.*\}|\[.*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQu
 ery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||++p.uuid:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];
 if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")===0&&(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,
 c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.shift(),e=p._queueHooks(a,b),f=function(){p.dequeue(a,b)};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),delete e.stop,d.call(a,f,e)),!c.length&&e&&e.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue
 :function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)(d=p._data(g[h],a+"queueHooks"))&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.pro
 p,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)~f.indexOf(" "+b[g]+" ")||(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>-1)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleCla
 ss:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.va
 l()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;
 if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,""+d),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b
 ,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:
 !0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selec
 tedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,argu
 ments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(
 ".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join(
 "\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[
 m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,k,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=[].slice.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click")){g=p(this),g.context=this;for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){i={},k=[],g[0]=f;for(d=0;d<q;d++)l=o[d],m=l.selector,i[m]===b&&(i[m]=g.is(m)),i[m]&&k.push(l);k.length&&u.push({elem:f,matches:k})}}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){j=u[d],c.currentTarget=j.elem;for(e=0;e<j.matches.length&&!c.isImmediatePropagationStopped();e++){l=j.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=
 l,h=((p.event.special[l.origType]||{}).handle||l.handler).apply(j.elem,r),h!==b&&(c.result=h,h===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&
 &g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{ready:{setup:p.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventList
 ener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStop
 ped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(t
 his.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simul
 ate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(t
 his,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown m
 ouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bd(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)Z(a,b[e],c,d)}function be(a,b,c,d,e,f){var g,h=$.setFilters[b.toLowerCase()];return h||Z.error(b),(a||!(g=e))&&bd(a||"*",d,g=[],e),g.length>0?h(g,c,f):[]}function bf(a,c,d,e,f){var g,h,i,j,k,l,m,n,p=0,q=f.length,s=L.POS,t=new RegExp("^"+s.source+"(?!"+r+")","i"),u=function(){var a=1,c=arguments.length-2;for(;a<c;a++)arguments[a]===b&&(g[a]=b)};for(;p<q;p++){s.exec(""),a=f[p],j=[],i=0,k=e;while(g=s.exec(a)){n=s.lastIndex=g.index+g[0].length;if(n>i){m=a.slice(i,g.index),i=n,l=[c],B.test(m)&&(k&&(l=k),k=e);if(h=H.test(m))m=m.slice(0,-5).replace(B,"$&*");g.length>1&&g[0]
 .replace(t,u),k=be(m,g[1],g[2],l,k,h)}}k?(j=j.concat(k),(m=a.slice(i))&&m!==")"?B.test(m)?bd(m,j,d,e):Z(m,c,d,e?e.concat(k):k):o.apply(d,j)):Z(a,c,d,e)}return q===1?d:Z.uniqueSort(d)}function bg(a,b,c){var d,e,f,g=[],i=0,j=D.exec(a),k=!j.pop()&&!j.pop(),l=k&&a.match(C)||[""],m=$.preFilter,n=$.filter,o=!c&&b!==h;for(;(e=l[i])!=null&&k;i++){g.push(d=[]),o&&(e=" "+e);while(e){k=!1;if(j=B.exec(e))e=e.slice(j[0].length),k=d.push({part:j.pop().replace(A," "),captures:j});for(f in n)(j=L[f].exec(e))&&(!m[f]||(j=m[f](j,b,c)))&&(e=e.slice(j.shift().length),k=d.push({part:f,captures:j}));if(!k)break}}return k||Z.error(a),g}function bh(a,b,e){var f=b.dir,g=m++;return a||(a=function(a){return a===e}),b.first?function(b,c){while(b=b[f])if(b.nodeType===1)return a(b,c)&&b}:function(b,e){var h,i=g+"."+d,j=i+"."+c;while(b=b[f])if(b.nodeType===1){if((h=b[q])===j)return b.sizset;if(typeof h=="string"&&h.indexOf(i)===0){if(b.sizset)return b}else{b[q]=j;if(a(b,e))return b.sizset=!0,b;b.sizset=!1}}}}func
 tion bi(a,b){return a?function(c,d){var e=b(c,d);return e&&a(e===!0?c:e,d)}:b}function bj(a,b,c){var d,e,f=0;for(;d=a[f];f++)$.relative[d.part]?e=bh(e,$.relative[d.part],b):(d.captures.push(b,c),e=bi(e,$.filter[d.part].apply(null,d.captures)));return e}function bk(a){return function(b,c){var d,e=0;for(;d=a[e];e++)if(d(b,c))return!0;return!1}}var c,d,e,f,g,h=a.document,i=h.documentElement,j="undefined",k=!1,l=!0,m=0,n=[].slice,o=[].push,q=("sizcache"+Math.random()).replace(".",""),r="[\\x20\\t\\r\\n\\f]",s="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",t=s.replace("w","w#"),u="([*^$|!~]?=)",v="\\["+r+"*("+s+")"+r+"*(?:"+u+r+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+t+")|)|)"+r+"*\\]",w=":("+s+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",x=":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",y=r+"*([\\x20\\t\\r\\n\\f>+~])"+r+"*",z="(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|"+v+"|"+w.replace(2,7)+"|[^\\\\(),])+",A=new RegExp("^"+r+"+|
 ((?:^|[^\\\\])(?:\\\\.)*)"+r+"+$","g"),B=new RegExp("^"+y),C=new RegExp(z+"?(?="+r+"*,|$)","g"),D=new RegExp("^(?:(?!,)(?:(?:^|,)"+r+"*"+z+")*?|"+r+"*(.*?))(\\)|$)"),E=new RegExp(z.slice(19,-6)+"\\x20\\t\\r\\n\\f>+~])+|"+y,"g"),F=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,G=/[\x20\t\r\n\f]*[+~]/,H=/:not\($/,I=/h\d/i,J=/input|select|textarea|button/i,K=/\\(?!\\)/g,L={ID:new RegExp("^#("+s+")"),CLASS:new RegExp("^\\.("+s+")"),NAME:new RegExp("^\\[name=['\"]?("+s+")['\"]?\\]"),TAG:new RegExp("^("+s.replace("[-","[-\\*")+")"),ATTR:new RegExp("^"+v),PSEUDO:new RegExp("^"+w),CHILD:new RegExp("^:(only|nth|last|first)-child(?:\\("+r+"*(even|odd|(([+-]|)(\\d*)n|)"+r+"*(?:([+-]|)"+r+"*(\\d+)|))"+r+"*\\)|)","i"),POS:new RegExp(x,"ig"),needsContext:new RegExp("^"+r+"*[>+~]|"+x,"i")},M={},N=[],O={},P=[],Q=function(a){return a.sizzleFilter=!0,a},R=function(a){return function(b){return b.nodeName.toLowerCase()==="input"&&b.type===a}},S=function(a){return function(b){var c=b.nodeName.toLowerCase();return
 (c==="input"||c==="button")&&b.type===a}},T=function(a){var b=!1,c=h.createElement("div");try{b=a(c)}catch(d){}return c=null,b},U=T(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),V=T(function(a){a.id=q+0,a.innerHTML="<a name='"+q+"'></a><div name='"+q+"'></div>",i.insertBefore(a,i.firstChild);var b=h.getElementsByName&&h.getElementsByName(q).length===2+h.getElementsByName(q+0).length;return g=!h.getElementById(q),i.removeChild(a),b}),W=T(function(a){return a.appendChild(h.createComment("")),a.getElementsByTagName("*").length===0}),X=T(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==j&&a.firstChild.getAttribute("href")==="#"}),Y=T(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||a.getElementsByClassName("e").length===0?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length!=
 =1)}),Z=function(a,b,c,d){c=c||[],b=b||h;var e,f,g,i,j=b.nodeType;if(j!==1&&j!==9)return[];if(!a||typeof a!="string")return c;g=ba(b);if(!g&&!d)if(e=F.exec(a))if(i=e[1]){if(j===9){f=b.getElementById(i);if(!f||!f.parentNode)return c;if(f.id===i)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(i))&&bb(b,f)&&f.id===i)return c.push(f),c}else{if(e[2])return o.apply(c,n.call(b.getElementsByTagName(a),0)),c;if((i=e[3])&&Y&&b.getElementsByClassName)return o.apply(c,n.call(b.getElementsByClassName(i),0)),c}return bm(a,b,c,d,g)},$=Z.selectors={cacheLength:50,match:L,order:["ID","TAG"],attrHandle:{},createPseudo:Q,find:{ID:g?function(a,b,c){if(typeof b.getElementById!==j&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==j&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==j&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:W?function(a,b){if(typeof b.getElementsByTagName!==j)retur
 n b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(K,""),a[3]=(a[4]||a[5]||"").replace(K,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||Z.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&Z.error(a[0]),a},PSEUDO:function(a){var b,c=a[4];return L.CHILD.test(a[0])?null:(c&&(b=D.exec(c))&&b.pop()&&(a[0]=a[0].slice(0,b[0].length-c.length-1),c=b[0].slice(0,-1)),a.splice(2,3,c||a[3]),a)}},filter:{ID:g?function(a){return a=a.replace(K,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(K,""),function(b){var c=typeof b.getAttributeNode!==j
 &&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(K,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=M[a];return b||(b=M[a]=new RegExp("(^|"+r+")"+a+"("+r+"|$)"),N.push(a),N.length>$.cacheLength&&delete M[N.shift()]),function(a){return b.test(a.className||typeof a.getAttribute!==j&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return b?function(d){var e=Z.attr(d,a),f=e+"";if(e==null)return b==="!=";switch(b){case"=":return f===c;case"!=":return f!==c;case"^=":return c&&f.indexOf(c)===0;case"*=":return c&&f.indexOf(c)>-1;case"$=":return c&&f.substr(f.length-c.length)===c;case"~=":return(" "+f+" ").indexOf(c)>-1;case"|=":return f===c||f.substr(0,c.length+1)===c+"-"}}:function(b){return Z.attr(b,a)!=null}},CHILD:function(a,b,c,d){if(a==="nth"){var e=m++;return function(a){var b,f,g=0,h=a;if(c===1&&d===0)return!0;b=a.parentNode;if(b&&(b[q]!==e||!a.sizset)){for(
 h=b.firstChild;h;h=h.nextSibling)if(h.nodeType===1){h.sizset=++g;if(h===a)break}b[q]=e}return f=a.sizset-d,c===0?f===0:f%c===0&&f/c>=0}}return function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b,c,d){var e=$.pseudos[a]||$.pseudos[a.toLowerCase()];return e||Z.error("unsupported pseudo: "+a),e.sizzleFilter?e(b,c,d):e}},pseudos:{not:Q(function(a,b,c){var d=bl(a.replace(A,"$1"),b,c);return function(a){return!d(a)}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!$.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.no
 deType)===3||b===4)return!1;a=a.nextSibling}return!0},contains:Q(function(a){return function(b){return(b.textContent||b.innerText||bc(b)).indexOf(a)>-1}}),has:Q(function(a){return function(b){return Z(a,b).length>0}}),header:function(a){return I.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:R("radio"),checkbox:R("checkbox"),file:R("file"),password:R("password"),image:R("image"),submit:S("submit"),reset:S("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return J.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b,c){return c?a.slice(1):[a[0]]},last:function(a,b,c){var d=a.pop();return c?a:[d]},even:function(
 a,b,c){var d=[],e=c?1:0,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},odd:function(a,b,c){var d=[],e=c?0:1,f=a.length;for(;e<f;e=e+2)d.push(a[e]);return d},lt:function(a,b,c){return c?a.slice(+b):a.slice(0,+b)},gt:function(a,b,c){return c?a.slice(0,+b+1):a.slice(+b+1)},eq:function(a,b,c){var d=a.splice(+b,1);return c?a:d}}};$.setFilters.nth=$.setFilters.eq,$.filters=$.pseudos,X||($.attrHandle={href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}}),V&&($.order.push("NAME"),$.find.NAME=function(a,b){if(typeof b.getElementsByName!==j)return b.getElementsByName(a)}),Y&&($.order.splice(1,0,"CLASS"),$.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!==j&&!c)return b.getElementsByClassName(a)});try{n.call(i.childNodes,0)[0].nodeType}catch(_){n=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}var ba=Z.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},bb=Z.contains=i.compa
 reDocumentPosition?function(a,b){return!!(a.compareDocumentPosition(b)&16)}:i.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc=Z.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=bc(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=bc(b);return c};Z.attr=function(a,b){var c,d=ba(a);return d||(b=b.toLowerCase()),$.attrHandle[b]?$.attrHandle[b](a):U||d?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},Z.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},[0,0].sort(function(){return l=0}),i.compareDocumentPosition?e=function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPos
 ition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:(e=function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],g=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return f(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)g.unshift(j),j=j.parentNode;c=e.length,d=g.length;for(var l=0;l<c&&l<d;l++)if(e[l]!==g[l])return f(e[l],g[l]);return l===c?f(a,g[l],-1):f(e[l],b,1)},f=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),Z.uniqueSort=function(a){var b,c=1;if(e){k=l,a.sort(e);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1)}return a};var bl=Z.compile=function(a,b,c){var d,e,f,g=O[a];if(g&&g.context===b)return g;e=bg(a,b,c);for(f=0;d=e[f];f++)e[f]=bj(d,b,c);return g=O[a]=bk(e),g.context=b,g.runs=g.dirruns=0,P.push(a),P.length>$.cacheLength&&delete O[P.shift()],g};Z.matches=function(a,b){return Z(a,null,null,b)},Z.matchesSel
 ector=function(a,b){return Z(b,null,null,[a]).length>0};var bm=function(a,b,e,f,g){a=a.replace(A,"$1");var h,i,j,k,l,m,p,q,r,s=a.match(C),t=a.match(E),u=b.nodeType;if(L.POS.test(a))return bf(a,b,e,f,s);if(f)h=n.call(f,0);else if(s&&s.length===1){if(t.length>1&&u===9&&!g&&(s=L.ID.exec(t[0]))){b=$.find.ID(s[1],b,g)[0];if(!b)return e;a=a.slice(t.shift().length)}q=(s=G.exec(t[0]))&&!s.index&&b.parentNode||b,r=t.pop(),m=r.split(":not")[0];for(j=0,k=$.order.length;j<k;j++){p=$.order[j];if(s=L[p].exec(m)){h=$.find[p]((s[1]||"").replace(K,""),q,g);if(h==null)continue;m===r&&(a=a.slice(0,a.length-r.length)+m.replace(L[p],""),a||o.apply(e,n.call(h,0)));break}}}if(a){i=bl(a,b,g),d=i.dirruns++,h==null&&(h=$.find.TAG("*",G.test(a)&&b.parentNode||b));for(j=0;l=h[j];j++)c=i.runs++,i(l,b)&&e.push(l)}return e};h.querySelectorAll&&function(){var a,b=bm,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[],f=[":active"],g=i.matchesSelector||i.mozMatchesSelector||i.webkitMatchesSelector||i.o
 MatchesSelector||i.msMatchesSelector;T(function(a){a.innerHTML="<select><option selected></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+r+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),T(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+r+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=e.length&&new RegExp(e.join("|")),bm=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a)))if(d.nodeType===9)try{return o.apply(f,n.call(d.querySelectorAll(a),0)),f}catch(i){}else if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){var j=d.getAttribute("id"),k=j||q,l=G.test(a)&&d.parentNode||d;j?k=k.replace(c,"\\$&"):d.setAttribute("id",k);try{return o.apply(f,n.call(l.querySelectorAll(a.replace(C,"[id='"+k+"'] $&")),0)),f}catch(i){}finally{j||d.removeAttribute("id")}}return b
 (a,d,f,g,h)},g&&(T(function(b){a=g.call(b,"div");try{g.call(b,"[test!='']:sizzle"),f.push($.match.PSEUDO)}catch(c){}}),f=new RegExp(f.join("|")),Z.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!ba(b)&&!f.test(c)&&(!e||!e.test(c)))try{var h=g.call(b,c);if(h||a||b.document&&b.document.nodeType!==11)return h}catch(i){}return Z(c,null,null,[b]).length>0})}(),Z.attr=p.attr,p.find=Z,p.expr=Z.selectors,p.expr[":"]=p.expr.pseudos,p.unique=Z.uniqueSort,p.text=Z.getText,p.isXMLDoc=Z.isXML,p.contains=Z.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice
 (e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.
 merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.
 map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new Reg
 Exp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[
 0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(
 a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nod
 eType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function()
 {p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=(c[0]||c).ownerDocument||c[0]||c,typeof c.createDocumentFragment=="undefined"&&(c=e),a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p
 .fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return 
 d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=0,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(g=b===e&&bA;(h=a[s])!=null;s++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{g=g||bk(b),l=l||g.appendChild(b.createElement("div")),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(f=n.length-1;f>=0;--f)p.nodeName(n[f],"tbody")&&!n[f].childNodes.length&&n[f].parentNode.removeChild(n[f])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l=g.lastChild}h.nodeType?t.push(h):t=p.merge(t,h)}l&&(g.removeChild(l),h=l=g=null);if(!p.support.appendChecked)for(s=0;(h=t[s])!=null;s++)p.nodeName(h,"input")?bG(h):type
 of h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(s=0;(h=t[s])!=null;s++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[s+1,0].concat(r)),s+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(ms
 ie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^margin/,bO=new RegExp("^("+q+")(.*)$","i"),bP=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bQ=new RegExp("^([-+])=("+q+")","i"),bR={},bS={position:"absolute",visibility:"hidden",display:"block"},bT={letterSpacing:0,fontWeight:400,lineHeight:1},bU=["Top","Right","Bottom","Left"],bV=["Webkit","O","Moz","ms"],bW=p.fn.toggle;p.fn.extend({css:funct
 ion(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return bZ(this,!0)},hide:function(){return bZ(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bW.apply(this,arguments):this.each(function(){(c?a:bY(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bX(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bQ.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&is
 NaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bX(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bT&&(f=bT[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(a,b){var c,d,e,f,g=getComputedStyle(a,null),h=a.style;return g&&(c=g[b],c===""&&!p.contains(a.ownerDocument.documentElement,a)&&(c=p.style(a,b)),bP.test(c)&&bN.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=c,c=g.width,h.width=d,h.minWidth=e,h.maxWidth=f)),c}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bP.test(e)&&!bM.te
 st(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0||bH(a,"display")!=="none"?ca(a,b,d):p.swap(a,bS,function(){return ca(a,b,d)})},set:function(a,c,d){return b$(a,c,d?b_(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarg
 inRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bP.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bU[d]+b]=e[d]||e[d-2]||e[0];return f}},bN.test(a)||(p.cssHooks[a+b].set=b$)});var cc=/%20/g,cd=/\[\]$/,ce=/\r?\n/g,cf=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,cg=/^(?:select|t
 extarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||cg.test(this.nodeName)||cf.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(ce,"\r\n")}}):{name:b.name,value:c.replace(ce,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ch(d,a[d],c,f);return e.join("&").replace(cc,"+")};var ci,cj,ck=/#.*$/,cl=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cm=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,cn=/^(?:GET|HEAD)$/
 ,co=/^\/\//,cp=/\?/,cq=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cr=/([?&])_=[^&]*/,cs=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,ct=p.fn.load,cu={},cv={},cw=["*/"]+["*"];try{ci=f.href}catch(cx){ci=e.createElement("a"),ci.href="",ci=ci.href}cj=cs.exec(ci.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&ct)return ct.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cq,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({ty
 pe:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cA(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cA(a,b),a},ajaxSettings:{url:ci,isLocal:cm.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cw},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cy(cu),ajaxTransport:cy(cv),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cB(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHea
 der("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cC(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=""+(c||y),k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cl.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return
  c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(ck,"").replace(co,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=cs.exec(l.url.toLowerCase()),l.crossDomain=!(!i||i[1]==cj[1]&&i[2]==cj[2]&&(i[3]||(i[1]==="http:"?80:443))==(cj[3]||(cj[1]==="http:"?80:443)))),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cz(cu,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!cn.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cp.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cr,"$1_="+z);l.url=A+(A===
 l.url?(cp.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cw+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cz(cv,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cD=[],cE=/\?/,cF=/(=)\?(?=&|$)|\?\?/,cG=p.now();p.ajaxSetup({j
 sonp:"callback",jsonpCallback:function(){var a=cD.pop()||p.expando+"_"+cG++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cF.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cF.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cF,"$1"+f):m?c.data=i.replace(cF,"$1"+f):k&&(c.url+=(cE.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cD.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":fu
 nction(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cH,cI=a.ActiveXObject?function(){for(var a in cH)cH[a](0,1)}:!1,cJ=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cK()||cL()}:cK,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){v
 ar d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cI&&delete cH[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cJ,cI&&(cH||(cH={},p(a).unload(cI)),cH[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});
 var cM,cN,cO=/^(?:toggle|show|hide)$/,cP=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cQ=/queueHooks$/,cR=[cX],cS={"*":[function(a,b){var c,d,e,f=this.createTween(a,b),g=cP.exec(b),h=f.cur(),i=+h||0,j=1;if(g){c=+g[2],d=g[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&i){i=p.css(f.elem,a,!0)||c||1;do e=j=j||".5",i=i/j,p.style(f.elem,a,i+d),j=f.cur()/h;while(j!==1&&j!==e)}f.unit=d,f.start=i,f.end=g[1]?i+(g[1]+1)*c:c}return f}]};p.Animation=p.extend(cV,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cS[c]=cS[c]||[],cS[c].unshift(b)},prefilter:function(a,b){b?cR.unshift(a):cR.push(a)}}),p.Tween=cY,cY.prototype={constructor:cY,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cY.propHooks[this.prop];return a&&a.get?a.get(this):cY.propHooks._default.get(this)},run:function(a){var b,c=cY.prop
 Hooks[this.prop];return this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration),this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cY.propHooks._default.set(this),this}},cY.prototype.init.prototype=cY.prototype,cY.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cY.propHooks.scrollTop=cY.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,argum
 ents):this.animate(cZ(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bY).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cV(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cQ.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:cZ("show"),slideUp:cZ("hide"),slideToggle:cZ("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.a
 nimate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration

<TRUNCATED>

[32/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java b/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
deleted file mode 100644
index ff14986..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegate.java
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.lang.String.format;
-import static java.util.Arrays.fill;
-import static java.util.UUID.randomUUID;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_FIELD_NAMES;
-import static org.taverna.server.master.defaults.Default.CERTIFICATE_TYPE;
-import static org.taverna.server.master.defaults.Default.CREDENTIAL_FILE_SIZE_LIMIT;
-import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.rmi.RemoteException;
-import java.security.GeneralSecurityException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-import javax.security.auth.x500.X500Principal;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.UriBuilder;
-import javax.xml.ws.handler.MessageContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.taverna.server.localworker.remote.ImplementationException;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.common.Trust;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-import org.taverna.server.master.interfaces.File;
-import org.taverna.server.master.interfaces.TavernaSecurityContext;
-import org.taverna.server.master.utils.UsernamePrincipal;
-
-/**
- * Implementation of a security context.
- * 
- * @author Donal Fellows
- */
-public abstract class SecurityContextDelegate implements TavernaSecurityContext {
-	Log log = LogFactory.getLog("Taverna.Server.Worker");
-	private final UsernamePrincipal owner;
-	private final List<Credential> credentials = new ArrayList<>();
-	private final List<Trust> trusted = new ArrayList<>();
-	private final RemoteRunDelegate run;
-	private final Object lock = new Object();
-	final SecurityContextFactory factory;
-
-	private transient Keystore keystore;
-	private transient Map<URI, String> uriToAliasMap;
-
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected SecurityContextDelegate(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		this.run = run;
-		this.owner = owner;
-		this.factory = factory;
-	}
-
-	@Override
-	public SecurityContextFactory getFactory() {
-		return factory;
-	}
-
-	@Override
-	public UsernamePrincipal getOwner() {
-		return owner;
-	}
-
-	@Override
-	public Credential[] getCredentials() {
-		synchronized (lock) {
-			return credentials.toArray(new Credential[credentials.size()]);
-		}
-	}
-
-	/**
-	 * Get the human-readable name of a principal.
-	 * 
-	 * @param principal
-	 *            The principal being decoded.
-	 * @return A name.
-	 */
-	protected final String getPrincipalName(X500Principal principal) {
-		return factory.x500Utils.getName(principal, CERTIFICATE_FIELD_NAMES);
-	}
-
-	/**
-	 * Cause the current state to be flushed to the database.
-	 */
-	protected final void flushToDB() {
-		factory.db.flushToDisk(run);
-	}
-
-	@Override
-	public void addCredential(Credential toAdd) {
-		synchronized (lock) {
-			int idx = credentials.indexOf(toAdd);
-			if (idx != -1)
-				credentials.set(idx, toAdd);
-			else
-				credentials.add(toAdd);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public void deleteCredential(Credential toDelete) {
-		synchronized (lock) {
-			credentials.remove(toDelete);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public Trust[] getTrusted() {
-		synchronized (lock) {
-			return trusted.toArray(new Trust[trusted.size()]);
-		}
-	}
-
-	@Override
-	public void addTrusted(Trust toAdd) {
-		synchronized (lock) {
-			int idx = trusted.indexOf(toAdd);
-			if (idx != -1)
-				trusted.set(idx, toAdd);
-			else
-				trusted.add(toAdd);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public void deleteTrusted(Trust toDelete) {
-		synchronized (lock) {
-			trusted.remove(toDelete);
-			flushToDB();
-		}
-	}
-
-	@Override
-	public abstract void validateCredential(Credential c)
-			throws InvalidCredentialException;
-
-	@Override
-	public void validateTrusted(Trust t) throws InvalidCredentialException {
-		InputStream contentsAsStream;
-		if (t.certificateBytes != null && t.certificateBytes.length > 0) {
-			contentsAsStream = new ByteArrayInputStream(t.certificateBytes);
-			t.certificateFile = null;
-		} else if (t.certificateFile == null
-				|| t.certificateFile.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty certificateFile");
-		else {
-			contentsAsStream = contents(t.certificateFile);
-			t.certificateBytes = null;
-		}
-		t.serverName = null;
-		if (t.fileType == null || t.fileType.trim().isEmpty())
-			t.fileType = CERTIFICATE_TYPE;
-		t.fileType = t.fileType.trim();
-		try {
-			t.loadedCertificates = CertificateFactory.getInstance(t.fileType)
-					.generateCertificates(contentsAsStream);
-			t.serverName = new ArrayList<>(t.loadedCertificates.size());
-			for (Certificate c : t.loadedCertificates)
-				t.serverName.add(getPrincipalName(((X509Certificate) c)
-						.getSubjectX500Principal()));
-		} catch (CertificateException e) {
-			throw new InvalidCredentialException(e);
-		} catch (ClassCastException e) {
-			// Do nothing; truncates the list of server names
-		}
-	}
-
-	@Override
-	public void initializeSecurityFromContext(SecurityContext securityContext)
-			throws Exception {
-		// This is how to get the info from Spring Security
-		Authentication auth = securityContext.getAuthentication();
-		if (auth == null)
-			return;
-		auth.getPrincipal();
-		// do nothing else in this implementation
-	}
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// do nothing in this implementation
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders context) {
-		// do nothing in this implementation
-	}
-
-	private UriBuilder getUB() {
-		return factory.uriSource.getRunUriBuilder(run);
-	}
-
-	private RunDatabaseDAO getDAO() {
-		return ((RunDatabase) factory.db).dao;
-	}
-
-	@Nullable
-	private List<X509Certificate> getCerts(URI uri) throws IOException,
-			GeneralSecurityException {
-		return factory.certFetcher.getTrustsForURI(uri);
-	}
-
-	private void installLocalPasswordCredential(List<Credential> credentials,
-			List<Trust> trusts) throws InvalidCredentialException, IOException,
-			GeneralSecurityException {
-		Credential.Password pw = new Credential.Password();
-		pw.id = "run:self";
-		pw.username = PREFIX + run.id;
-		pw.password = getDAO().getSecurityToken(run.id);
-		UriBuilder ub = getUB().segment("").fragment(factory.httpRealm);
-		pw.serviceURI = ub.build();
-		validateCredential(pw);
-		log.info("issuing self-referential credential for " + pw.serviceURI);
-		credentials.add(pw);
-		List<X509Certificate> myCerts = getCerts(pw.serviceURI);
-		if (myCerts != null && myCerts.size() > 0) {
-			Trust t = new Trust();
-			t.loadedCertificates = getCerts(pw.serviceURI);
-			trusts.add(t);
-		}
-	}
-
-	/**
-	 * Builds and transfers a keystore with suitable credentials to the back-end
-	 * workflow execution engine.
-	 * 
-	 * @throws GeneralSecurityException
-	 *             If the manipulation of the keystore, keys or certificates
-	 *             fails.
-	 * @throws IOException
-	 *             If there are problems building the data (should not happen).
-	 * @throws RemoteException
-	 *             If the conveyancing fails.
-	 */
-	@Override
-	public final void conveySecurity() throws GeneralSecurityException,
-			IOException, ImplementationException {
-		RemoteSecurityContext rc = run.run.getSecurityContext();
-
-		List<Trust> trusted = new ArrayList<>(this.trusted);
-		this.trusted.clear();
-		List<Credential> credentials = new ArrayList<>(this.credentials);
-		this.credentials.clear();
-
-		try {
-			installLocalPasswordCredential(credentials, trusted);
-		} catch (Exception e) {
-			log.warn("failed to construct local credential: "
-					+ "interaction service will fail", e);
-		}
-
-		char[] password = null;
-		try {
-			password = generateNewPassword();
-
-			log.info("constructing merged keystore");
-			Truststore truststore = new Truststore(password);
-			Keystore keystore = new Keystore(password);
-			Map<URI, String> uriToAliasMap = new HashMap<>();
-			int trustedCount = 0, keyCount = 0;
-
-			synchronized (lock) {
-				try {
-					for (Trust t : trusted) {
-						if (t == null || t.loadedCertificates == null)
-							continue;
-						for (Certificate cert : t.loadedCertificates)
-							if (cert != null) {
-								truststore.addCertificate(cert);
-								trustedCount++;
-							}
-					}
-
-					this.uriToAliasMap = uriToAliasMap;
-					this.keystore = keystore;
-					for (Credential c : credentials) {
-						addCredentialToKeystore(c);
-						keyCount++;
-					}
-				} finally {
-					this.uriToAliasMap = null;
-					this.keystore = null;
-					credentials.clear();
-					trusted.clear();
-					flushToDB();
-				}
-			}
-
-			byte[] trustbytes = null, keybytes = null;
-			try {
-				trustbytes = truststore.serialize();
-				keybytes = keystore.serialize();
-
-				// Now we've built the security information, ship it off...
-
-				log.info("transfering merged truststore with " + trustedCount
-						+ " entries");
-				rc.setTruststore(trustbytes);
-
-				log.info("transfering merged keystore with " + keyCount
-						+ " entries");
-				rc.setKeystore(keybytes);
-			} finally {
-				if (trustbytes != null)
-					fill(trustbytes, (byte) 0);
-				if (keybytes != null)
-					fill(keybytes, (byte) 0);
-			}
-			rc.setPassword(password);
-
-			log.info("transferring serviceURL->alias map with "
-					+ uriToAliasMap.size() + " entries");
-			rc.setUriToAliasMap(uriToAliasMap);
-		} finally {
-			if (password != null)
-				fill(password, ' ');
-		}
-
-		synchronized (lock) {
-			conveyExtraSecuritySettings(rc);
-		}
-	}
-
-	/**
-	 * Hook that allows additional information to be conveyed to the remote run.
-	 * 
-	 * @param remoteSecurityContext
-	 *            The remote resource that information would be passed to.
-	 * @throws IOException
-	 *             If anything goes wrong with the communication.
-	 */
-	protected void conveyExtraSecuritySettings(
-			RemoteSecurityContext remoteSecurityContext) throws IOException {
-		// Does nothing by default; overrideable
-	}
-
-	/**
-	 * @return A new password with a reasonable level of randomness.
-	 */
-	protected final char[] generateNewPassword() {
-		return randomUUID().toString().toCharArray();
-	}
-
-	/**
-	 * Adds a credential to the current keystore.
-	 * 
-	 * @param alias
-	 *            The alias to create within the keystore.
-	 * @param c
-	 *            The key-pair.
-	 * @throws KeyStoreException
-	 */
-	protected final void addKeypairToKeystore(String alias, Credential c)
-			throws KeyStoreException {
-		if (c.loadedKey == null)
-			throw new KeyStoreException("critical: credential was not verified");
-		if (uriToAliasMap.containsKey(c.serviceURI))
-			log.warn("duplicate URI in alias mapping: " + c.serviceURI);
-		keystore.addKey(alias, c.loadedKey, c.loadedTrustChain);
-		uriToAliasMap.put(c.serviceURI, alias);
-	}
-
-	/**
-	 * Adds a credential to the current keystore.
-	 * 
-	 * @param c
-	 *            The credential to add.
-	 * @throws KeyStoreException
-	 */
-	public abstract void addCredentialToKeystore(Credential c)
-			throws KeyStoreException;
-
-	/**
-	 * Read a file up to {@value #FILE_SIZE_LIMIT}kB in size.
-	 * 
-	 * @param name
-	 *            The path name of the file, relative to the context run's
-	 *            working directory.
-	 * @return A stream of the file's contents.
-	 * @throws InvalidCredentialException
-	 *             If anything goes wrong.
-	 */
-	final InputStream contents(String name) throws InvalidCredentialException {
-		try {
-			File f = (File) factory.fileUtils.getDirEntry(run, name);
-			long size = f.getSize();
-			if (size > CREDENTIAL_FILE_SIZE_LIMIT * 1024)
-				throw new InvalidCredentialException(CREDENTIAL_FILE_SIZE_LIMIT
-						+ "kB limit hit");
-			return new ByteArrayInputStream(f.getContents(0, (int) size));
-		} catch (NoDirectoryEntryException | FilesystemAccessException e) {
-			throw new InvalidCredentialException(e);
-		} catch (ClassCastException e) {
-			throw new InvalidCredentialException("not a file", e);
-		}
-	}
-
-	@Override
-	public Set<String> getPermittedDestroyers() {
-		return run.getDestroyers();
-	}
-
-	@Override
-	public void setPermittedDestroyers(Set<String> destroyers) {
-		run.setDestroyers(destroyers);
-	}
-
-	@Override
-	public Set<String> getPermittedUpdaters() {
-		return run.getWriters();
-	}
-
-	@Override
-	public void setPermittedUpdaters(Set<String> updaters) {
-		run.setWriters(updaters);
-	}
-
-	@Override
-	public Set<String> getPermittedReaders() {
-		return run.getReaders();
-	}
-
-	@Override
-	public void setPermittedReaders(Set<String> readers) {
-		run.setReaders(readers);
-	}
-
-	/**
-	 * Reinstall the credentials and the trust extracted from serialization to
-	 * the database.
-	 * 
-	 * @param credentials
-	 *            The credentials to reinstall.
-	 * @param trust
-	 *            The trusted certificates to reinstall.
-	 */
-	void setCredentialsAndTrust(Credential[] credentials, Trust[] trust) {
-		synchronized (lock) {
-			this.credentials.clear();
-			if (credentials != null)
-				for (Credential c : credentials)
-					try {
-						validateCredential(c);
-						this.credentials.add(c);
-					} catch (InvalidCredentialException e) {
-						log.warn("failed to revalidate credential: " + c, e);
-					}
-			this.trusted.clear();
-			if (trust != null)
-				for (Trust t : trust)
-					try {
-						validateTrusted(t);
-						this.trusted.add(t);
-					} catch (InvalidCredentialException e) {
-						log.warn("failed to revalidate trust assertion: " + t,
-								e);
-					}
-		}
-	}
-
-	static class SecurityStore {
-		private KeyStore ks;
-		private char[] password;
-
-		SecurityStore(char[] password) throws GeneralSecurityException {
-			this.password = password.clone();
-			ks = KeyStore.getInstance("UBER", "BC");
-			try {
-				ks.load(null, this.password);
-			} catch (IOException e) {
-				throw new GeneralSecurityException(
-						"problem initializing blank truststore", e);
-			}
-		}
-
-		final synchronized void setCertificate(String alias, Certificate c)
-				throws KeyStoreException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			ks.setCertificateEntry(alias, c);
-		}
-
-		final synchronized void setKey(String alias, Key key, Certificate[] trustChain)
-				throws KeyStoreException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			ks.setKeyEntry(alias, key, password, trustChain);
-		}
-
-		final synchronized byte[] serialize(boolean logIt)
-				throws GeneralSecurityException {
-			if (ks == null)
-				throw new IllegalStateException("store already written");
-			try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
-				ks.store(stream, password);
-				if (logIt)
-					LogFactory.getLog("Taverna.Server.Worker").debug(
-							"serialized UBER/BC truststore (size: " + ks.size()
-									+ ") with password \""
-									+ new String(password) + "\"");
-				return stream.toByteArray();
-			} catch (IOException e) {
-				throw new GeneralSecurityException(
-						"problem serializing keystore", e);
-			} finally {
-				ks = null;
-				fill(password, ' ');
-			}
-		}
-
-		@Override
-		protected final void finalize() {
-			fill(password, ' ');
-			ks = null;
-		}
-	}
-
-	/**
-	 * A trust store that can only be added to or serialized. Only trusted
-	 * certificates can be placed in it.
-	 * 
-	 * @author Donal Fellows
-	 */
-	class Truststore extends SecurityStore {
-		Truststore(char[] password) throws GeneralSecurityException {
-			super(password);
-		}
-
-		/**
-		 * Add a trusted certificate to the truststore. No certificates can be
-		 * added after the truststore is serialized.
-		 * 
-		 * @param cert
-		 *            The certificate (typically belonging to a root CA) to add.
-		 * @throws KeyStoreException
-		 *             If anything goes wrong.
-		 */
-		public void addCertificate(Certificate cert) throws KeyStoreException {
-			X509Certificate c = (X509Certificate) cert;
-			String alias = format("trustedcert#%s#%s#%s",
-					getPrincipalName(c.getSubjectX500Principal()),
-					getPrincipalName(c.getIssuerX500Principal()),
-					factory.x500Utils.getSerial(c));
-			setCertificate(alias, c);
-			if (log.isDebugEnabled() && factory.logSecurityDetails)
-				log.debug("added cert with alias \"" + alias + "\" of type "
-						+ c.getClass().getCanonicalName());
-		}
-
-		/**
-		 * Get the byte serialization of this truststore. This can only be
-		 * fetched exactly once.
-		 * 
-		 * @return The serialization.
-		 * @throws GeneralSecurityException
-		 *             If anything goes wrong.
-		 */
-		public byte[] serialize() throws GeneralSecurityException {
-			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
-		}
-	}
-
-	/**
-	 * A key store that can only be added to or serialized. Only keys can be
-	 * placed in it.
-	 * 
-	 * @author Donal Fellows
-	 */
-	class Keystore extends SecurityStore {
-		Keystore(char[] password) throws GeneralSecurityException {
-			super(password);
-		}
-
-		/**
-		 * Add a key to the keystore. No keys can be added after the keystore is
-		 * serialized.
-		 * 
-		 * @param alias
-		 *            The alias of the key.
-		 * @param key
-		 *            The secret/private key to add.
-		 * @param trustChain
-		 *            The trusted certificate chain of the key. Should be
-		 *            <tt>null</tt> for secret keys.
-		 * @throws KeyStoreException
-		 *             If anything goes wrong.
-		 */
-		public void addKey(String alias, Key key, Certificate[] trustChain)
-				throws KeyStoreException {
-			setKey(alias, key, trustChain);
-			if (log.isDebugEnabled() && factory.logSecurityDetails)
-				log.debug("added key with alias \"" + alias + "\" of type "
-						+ key.getClass().getCanonicalName());
-		}
-
-		/**
-		 * Get the byte serialization of this keystore. This can only be fetched
-		 * exactly once.
-		 * 
-		 * @return The serialization.
-		 * @throws GeneralSecurityException
-		 *             If anything goes wrong.
-		 */
-		public byte[] serialize() throws GeneralSecurityException {
-			return serialize(log.isDebugEnabled() && factory.logSecurityDetails);
-		}
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java b/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
deleted file mode 100644
index d36d2da..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextDelegateImpl.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2010-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.lang.String.format;
-import static javax.xml.ws.handler.MessageContext.HTTP_REQUEST_HEADERS;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.Charset;
-import java.rmi.RemoteException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.List;
-import java.util.Map;
-
-import javax.crypto.spec.SecretKeySpec;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.xml.ws.handler.MessageContext;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.taverna.server.localworker.remote.RemoteSecurityContext;
-import org.taverna.server.master.common.Credential;
-import org.taverna.server.master.exceptions.InvalidCredentialException;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
-
-/**
- * Factoring out of the part of the security context handling that actually
- * deals with the different types of credentials.
- * 
- * @author Donal Fellows
- */
-class SecurityContextDelegateImpl extends SecurityContextDelegate {
-	private static final char USERNAME_PASSWORD_SEPARATOR = '\u0000';
-	private static final String USERNAME_PASSWORD_KEY_ALGORITHM = "DUMMY";
-	/** What passwords are encoded as. */
-	private static final Charset UTF8 = Charset.forName("UTF-8");
-
-	private X500Utils x500Utils;
-
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected SecurityContextDelegateImpl(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		super(run, owner, factory);
-		this.x500Utils = factory.x500Utils;
-	}
-
-	@Override
-	public void validateCredential(Credential c)
-			throws InvalidCredentialException {
-		try {
-			if (c instanceof Credential.Password)
-				validatePasswordCredential((Credential.Password) c);
-			else if (c instanceof Credential.KeyPair)
-				validateKeyCredential((Credential.KeyPair) c);
-			else
-				throw new InvalidCredentialException("unknown credential type");
-		} catch (InvalidCredentialException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new InvalidCredentialException(e);
-		}
-	}
-
-	@Override
-	public void addCredentialToKeystore(Credential c) throws KeyStoreException {
-		try {
-			if (c instanceof Credential.Password)
-				addUserPassToKeystore((Credential.Password) c);
-			else if (c instanceof Credential.KeyPair)
-				addKeypairToKeystore((Credential.KeyPair) c);
-			else
-				throw new KeyStoreException("unknown credential type");
-		} catch (KeyStoreException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new KeyStoreException(e);
-		}
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * Tests whether the given username+password credential descriptor is valid.
-	 * If it is invalid, an exception will be thrown describing what the problem
-	 * is. Validation mainly consists of listing what the username is.
-	 * 
-	 * @param passwordDescriptor
-	 *            The credential descriptor to validate.
-	 * @throws InvalidCredentialException
-	 *             If the username is empty. NB: the password may be empty!
-	 *             That's legal (if unwise).
-	 */
-	protected void validatePasswordCredential(
-			Credential.Password passwordDescriptor)
-			throws InvalidCredentialException {
-		if (passwordDescriptor.username == null
-				|| passwordDescriptor.username.trim().isEmpty())
-			throw new InvalidCredentialException("absent or empty username");
-		if (passwordDescriptor.serviceURI == null)
-			throw new InvalidCredentialException("absent service URI");
-		String keyToSave = passwordDescriptor.username
-				+ USERNAME_PASSWORD_SEPARATOR + passwordDescriptor.password;
-		passwordDescriptor.loadedKey = encodeKey(keyToSave);
-		passwordDescriptor.loadedTrustChain = null;
-	}
-
-	private static Key encodeKey(String key) {
-		return new SecretKeySpec(key.getBytes(UTF8),
-				USERNAME_PASSWORD_KEY_ALGORITHM);
-	}
-
-	/**
-	 * Adds a username/password credential pair to the current keystore.
-	 * 
-	 * @param userpassCredential
-	 *            The username and password.
-	 * @throws KeyStoreException
-	 */
-	protected void addUserPassToKeystore(Credential.Password userpassCredential)
-			throws KeyStoreException {
-		String alias = format("password#%s",
-				userpassCredential.serviceURI.toASCIIString());
-		addKeypairToKeystore(alias, userpassCredential);
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	/**
-	 * Tests whether the given key-pair credential descriptor is valid. If it is
-	 * invalid, an exception will be thrown describing what the problem is.
-	 * 
-	 * @param keypairDescriptor
-	 *            The descriptor to validate.
-	 * @throws InvalidCredentialException
-	 *             If the descriptor is invalid
-	 * @throws KeyStoreException
-	 *             If we don't understand the keystore type or the contents of
-	 *             the keystore
-	 * @throws NoSuchAlgorithmException
-	 *             If the keystore is of a known type but we can't comprehend
-	 *             its security
-	 * @throws CertificateException
-	 *             If the keystore does not include enough information about the
-	 *             trust chain of the keypair
-	 * @throws UnrecoverableKeyException
-	 *             If we can't get the key out of the keystore
-	 * @throws IOException
-	 *             If we can't read the keystore for prosaic reasons (e.g., file
-	 *             absent)
-	 */
-	protected void validateKeyCredential(Credential.KeyPair keypairDescriptor)
-			throws InvalidCredentialException, KeyStoreException,
-			NoSuchAlgorithmException, CertificateException, IOException,
-			UnrecoverableKeyException {
-		if (keypairDescriptor.credentialName == null
-				|| keypairDescriptor.credentialName.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty credentialName");
-
-		InputStream contentsAsStream;
-		if (keypairDescriptor.credentialBytes != null
-				&& keypairDescriptor.credentialBytes.length > 0) {
-			contentsAsStream = new ByteArrayInputStream(
-					keypairDescriptor.credentialBytes);
-			keypairDescriptor.credentialFile = null;
-		} else if (keypairDescriptor.credentialFile == null
-				|| keypairDescriptor.credentialFile.trim().isEmpty())
-			throw new InvalidCredentialException(
-					"absent or empty credentialFile");
-		else {
-			contentsAsStream = contents(keypairDescriptor.credentialFile);
-			keypairDescriptor.credentialBytes = new byte[0];
-		}
-		if (keypairDescriptor.fileType == null
-				|| keypairDescriptor.fileType.trim().isEmpty())
-			keypairDescriptor.fileType = KeyStore.getDefaultType();
-		keypairDescriptor.fileType = keypairDescriptor.fileType.trim();
-
-		KeyStore ks = KeyStore.getInstance(keypairDescriptor.fileType);
-		char[] password = keypairDescriptor.unlockPassword.toCharArray();
-		ks.load(contentsAsStream, password);
-
-		try {
-			keypairDescriptor.loadedKey = ks.getKey(
-					keypairDescriptor.credentialName, password);
-		} catch (UnrecoverableKeyException ignored) {
-			keypairDescriptor.loadedKey = ks.getKey(
-					keypairDescriptor.credentialName, new char[0]);
-		}
-		if (keypairDescriptor.loadedKey == null)
-			throw new InvalidCredentialException(
-					"no such credential in key store");
-		keypairDescriptor.loadedTrustChain = ks
-				.getCertificateChain(keypairDescriptor.credentialName);
-		if (keypairDescriptor.loadedTrustChain == null
-				|| keypairDescriptor.loadedTrustChain.length == 0)
-			throw new InvalidCredentialException(
-					"could not establish trust chain for credential");
-	}
-
-	/**
-	 * Adds a key-pair to the current keystore.
-	 * 
-	 * @param c
-	 *            The key-pair.
-	 * @throws KeyStoreException
-	 */
-	protected void addKeypairToKeystore(Credential.KeyPair c)
-			throws KeyStoreException {
-		X509Certificate subjectCert = (X509Certificate) c.loadedTrustChain[0];
-		String alias = format("keypair#%s#%s#%s",
-				getPrincipalName(subjectCert.getSubjectX500Principal()),
-				getPrincipalName(subjectCert.getIssuerX500Principal()),
-				x500Utils.getSerial(subjectCert));
-		addKeypairToKeystore(alias, c);
-	}
-}
-
-/**
- * Special subclass that adds support for HELIO project security tokens.
- * 
- * @author Donal Fellows
- */
-class HelioSecurityContextDelegateImpl extends SecurityContextDelegateImpl {
-	/**
-	 * Initialise the context delegate.
-	 * 
-	 * @param run
-	 *            What workflow run is this for?
-	 * @param owner
-	 *            Who owns the workflow run?
-	 * @param factory
-	 *            What class built this object?
-	 */
-	protected HelioSecurityContextDelegateImpl(RemoteRunDelegate run,
-			UsernamePrincipal owner, SecurityContextFactory factory) {
-		super(run, owner, factory);
-	}
-
-	private Log log = LogFactory.getLog("Taverna.Server.Worker");
-	/** The name of the HTTP header holding the CIS token. */
-	private static final String HELIO_CIS_TOKEN = "X-Helio-CIS";
-	private transient String helioToken;
-
-	@Override
-	public void initializeSecurityFromSOAPContext(MessageContext context) {
-		// does nothing
-		@SuppressWarnings("unchecked")
-		Map<String, List<String>> headers = (Map<String, List<String>>) context
-				.get(HTTP_REQUEST_HEADERS);
-		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
-			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
-	}
-
-	@Override
-	public void initializeSecurityFromRESTContext(HttpHeaders context) {
-		// does nothing
-		MultivaluedMap<String, String> headers = context.getRequestHeaders();
-		if (factory.supportHelioToken && headers.containsKey(HELIO_CIS_TOKEN))
-			helioToken = headers.get(HELIO_CIS_TOKEN).get(0);
-	}
-
-	@Override
-	protected void conveyExtraSecuritySettings(RemoteSecurityContext rc)
-			throws RemoteException {
-		try {
-			if (factory.supportHelioToken && helioToken != null) {
-				if (factory.logSecurityDetails)
-					log.info("transfering HELIO CIS token: " + helioToken);
-				rc.setHelioToken(helioToken);
-			}
-		} finally {
-			helioToken = null;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java b/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
deleted file mode 100644
index cbccf34..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/SecurityContextFactory.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static java.security.Security.addProvider;
-import static java.security.Security.getProvider;
-import static java.security.Security.removeProvider;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
-
-import java.io.Serializable;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-
-import org.apache.commons.logging.Log;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.springframework.beans.factory.annotation.Required;
-import org.springframework.beans.factory.annotation.Value;
-import org.taverna.server.master.interfaces.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.CertificateChainFetcher;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.master.utils.UsernamePrincipal;
-import org.taverna.server.master.utils.X500Utils;
-
-/**
- * Singleton factory. Really is a singleton (and is also very trivial); the
- * singleton-ness is just about limiting the number of instances of this around
- * even when lots of serialization is going on.
- * 
- * @see Serializable
- * @author Donal Fellows
- */
-public class SecurityContextFactory implements
-		org.taverna.server.master.interfaces.SecurityContextFactory {
-	private static final long serialVersionUID = 12345678987654321L;
-	private static SecurityContextFactory instance;
-	transient RunDBSupport db;
-	transient FilenameUtils fileUtils;
-	transient X500Utils x500Utils;
-	transient UriBuilderFactory uriSource;
-	transient CertificateChainFetcher certFetcher;
-	transient String httpRealm;
-	private transient PasswordIssuer passwordIssuer;
-	private transient BouncyCastleProvider provider;
-
-	/**
-	 * Whether to support HELIO CIS tokens.
-	 */
-	@Value("${helio.cis.enableTokenPassing}")
-	boolean supportHelioToken;
-
-	/**
-	 * Whether to log the details of security (passwords, etc).
-	 */
-	@Value("${log.security.details}")
-	boolean logSecurityDetails;
-
-	private Log log() {
-		return getLog("Taverna.Server.Worker.Security");
-	}
-
-	private void installAsInstance(SecurityContextFactory handle) {
-		instance = handle;
-	}
-
-	@PreDestroy
-	void removeAsSingleton() {
-		installAsInstance(null);
-		try {
-			if (provider != null)
-				removeProvider(provider.getName());
-		} catch (SecurityException e) {
-			log().warn(
-					"failed to remove BouncyCastle security provider; "
-							+ "might be OK if configured in environment", e);
-		}
-	}
-
-	@PostConstruct
-	void setAsSingleton() {
-		installAsInstance(this);
-		if (getProvider(PROVIDER_NAME) == null)
-			try {
-				provider = new BouncyCastleProvider();
-				if (addProvider(provider) == -1)
-					provider = null;
-			} catch (SecurityException e) {
-				log().warn(
-						"failed to install BouncyCastle security provider; "
-								+ "might be OK if already configured", e);
-				provider = null;
-			}
-	}
-
-	@Required
-	public void setRunDatabase(RunDBSupport db) {
-		this.db = db;
-	}
-
-	@Required
-	public void setCertificateFetcher(CertificateChainFetcher fetcher) {
-		this.certFetcher = fetcher;
-	}
-
-	@Required
-	public void setFilenameConverter(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	@Required
-	public void setX500Utils(X500Utils x500Utils) {
-		this.x500Utils = x500Utils;
-	}
-
-	@Required
-	public void setUriSource(UriBuilderFactory uriSource) {
-		this.uriSource = uriSource;
-	}
-
-	@Required
-	public void setHttpRealm(String realm) {
-		this.httpRealm = realm; //${http.realmName}
-	}
-
-	@Required
-	public void setPasswordIssuer(PasswordIssuer issuer) {
-		this.passwordIssuer = issuer;
-	}
-
-	@Override
-	public SecurityContextDelegate create(TavernaRun run,
-			UsernamePrincipal owner) throws Exception {
-		Log log = log();
-		if (log.isDebugEnabled())
-			log.debug("constructing security context delegate for " + owner);
-		RemoteRunDelegate rrd = (RemoteRunDelegate) run;
-		return new HelioSecurityContextDelegateImpl(rrd, owner, this);
-	}
-
-	private Object readResolve() {
-		if (instance == null)
-			installAsInstance(this);
-		return instance;
-	}
-
-	public String issueNewPassword() {
-		return passwordIssuer.issue();
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java b/server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
deleted file mode 100644
index 793d291..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/SimpleFormattedCompletionNotifier.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import static org.taverna.server.master.defaults.Default.NOTIFY_MESSAGE_FORMAT;
-
-import java.text.MessageFormat;
-
-import org.springframework.beans.factory.annotation.Required;
-
-/**
- * Completion notifier that sends messages by email.
- * 
- * @author Donal Fellows
- */
-public class SimpleFormattedCompletionNotifier implements CompletionNotifier {
-	@Required
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	/**
-	 * @param subject
-	 *            The subject of the notification email.
-	 */
-	@Required
-	public void setSubject(String subject) {
-		this.subject = subject;
-	}
-
-	/**
-	 * @param messageFormat
-	 *            The template for the body of the message to send. Parameter #0
-	 *            will be substituted with the ID of the job, and parameter #1
-	 *            will be substituted with the exit code.
-	 */
-	public void setMessageFormat(String messageFormat) {
-		this.format = new MessageFormat(messageFormat);
-	}
-
-	private String name;
-	private String subject;
-	private MessageFormat format = new MessageFormat(NOTIFY_MESSAGE_FORMAT);
-
-	@Override
-	public String makeCompletionMessage(String name, RemoteRunDelegate run,
-			int code) {
-		return format.format(new Object[] { name, code });
-	}
-
-	@Override
-	public String makeMessageSubject(String name, RemoteRunDelegate run,
-			int code) {
-		return subject;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java b/server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
deleted file mode 100644
index cf67853..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/VelocityCompletionNotifier.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.taverna.server.master.worker;
-
-import java.io.StringWriter;
-
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.VelocityEngine;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.common.version.Version;
-import org.taverna.server.master.exceptions.NoListenerException;
-import org.taverna.server.master.interfaces.Listener;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-
-public class VelocityCompletionNotifier implements CompletionNotifier {
-	private String subject;
-	private VelocityEngine engine;
-	private Template template;
-	private String name;
-	private String templateName;
-	private UriBuilderFactory ubf;
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @param subject
-	 *            The subject of the notification email.
-	 */
-	@Required
-	public void setSubject(String subject) {
-		this.subject = subject;
-	}
-
-	/**
-	 * @param engine
-	 *            The configured Apache Velocity engine.
-	 */
-	@Required
-	public void setVelocityEngine(VelocityEngine engine) {
-		this.engine = engine;
-	}
-
-	/**
-	 * @param uriBuilderFactory
-	 *            The configured URI builder factory.
-	 */
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
-		this.ubf = uriBuilderFactory;
-	}
-
-	/**
-	 * @param name
-	 *            The name of the template.
-	 */
-	@Required
-	public void setName(String name) {
-		this.name = name;
-		this.templateName = getClass().getName() + "_" + name + ".vtmpl";
-	}
-
-	private Template getTemplate() {
-		if (template == null)
-			synchronized(this) {
-				if (template == null)
-					template = engine.getTemplate(templateName);
-			}
-		return template;
-	}
-
-	@Override
-	public String makeCompletionMessage(String name, RemoteRunDelegate run,
-			int code) {
-		VelocityContext ctxt = new VelocityContext();
-		ctxt.put("id", name);
-		ctxt.put("uriBuilder", ubf.getRunUriBuilder(run));
-		ctxt.put("name", run.getName());
-		ctxt.put("creationTime", run.getCreationTimestamp());
-		ctxt.put("startTime", run.getStartTimestamp());
-		ctxt.put("finishTime", run.getFinishTimestamp());
-		ctxt.put("expiryTime", run.getExpiry());
-		ctxt.put("serverVersion", Version.JAVA);
-		for (Listener l : run.getListeners())
-			if (l.getName().equals("io")) {
-				for (String p : l.listProperties())
-					try {
-						ctxt.put("prop_" + p, l.getProperty(p));
-					} catch (NoListenerException e) {
-						// Ignore...
-					}
-				break;
-			}
-		StringWriter sw = new StringWriter();
-		getTemplate().merge(ctxt, sw);
-		return sw.toString();
-	}
-
-	@Override
-	public String makeMessageSubject(String name, RemoteRunDelegate run,
-			int code) {
-		return subject;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java b/server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
deleted file mode 100644
index 1abe617..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/WorkerModel.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2010-2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.taverna.server.master.worker;
-
-import java.net.URI;
-import java.util.List;
-
-import org.taverna.server.master.common.Status;
-
-/**
- * Profile of the getters and setters in a worker system. Ensures that the
- * persisted state matches the public view on the state model at least fairly
- * closely.
- * 
- * @author Donal Fellows
- */
-public interface WorkerModel extends PolicyLimits {
-
-	/**
-	 * @param defaultLifetime
-	 *            how long a workflow run should live by default, in minutes.
-	 */
-	public abstract void setDefaultLifetime(int defaultLifetime);
-
-	/**
-	 * @return how long a workflow run should live by default, in minutes.
-	 */
-	public abstract int getDefaultLifetime();
-
-	/**
-	 * @param maxRuns
-	 *            the maximum number of extant workflow runs
-	 */
-	public abstract void setMaxRuns(int maxRuns);
-
-	/**
-	 * @param factoryProcessNamePrefix
-	 *            the prefix used for factory processes in RMI
-	 */
-	public abstract void setFactoryProcessNamePrefix(
-			String factoryProcessNamePrefix);
-
-	/**
-	 * @return the prefix used for factory processes in RMI
-	 */
-	public abstract String getFactoryProcessNamePrefix();
-
-	/**
-	 * @param executeWorkflowScript
-	 *            the script to run to actually run a workflow
-	 */
-	public abstract void setExecuteWorkflowScript(String executeWorkflowScript);
-
-	/**
-	 * @return the script to run to actually run a workflow
-	 */
-	public abstract String getExecuteWorkflowScript();
-
-	/**
-	 * @param extraArgs
-	 *            the extra arguments to pass into the workflow runner
-	 */
-	public abstract void setExtraArgs(String[] extraArgs);
-
-	/**
-	 * @return the extra arguments to pass into the workflow runner
-	 */
-	public abstract String[] getExtraArgs();
-
-	/**
-	 * @param waitSeconds
-	 *            the number of seconds to wait for subprocesses to start
-	 */
-	public abstract void setWaitSeconds(int waitSeconds);
-
-	/**
-	 * @return the number of seconds to wait for subprocesses to start
-	 */
-	public abstract int getWaitSeconds();
-
-	/**
-	 * @param sleepMS
-	 *            milliseconds to wait between polling for a started
-	 *            subprocess's status
-	 */
-	public abstract void setSleepMS(int sleepMS);
-
-	/**
-	 * @return milliseconds to wait between polling for a started subprocess's
-	 *         status
-	 */
-	public abstract int getSleepMS();
-
-	/**
-	 * @param serverWorkerJar
-	 *            the full path name of the file system access worker
-	 *            subprocess's implementation JAR
-	 */
-	public abstract void setServerWorkerJar(String serverWorkerJar);
-
-	/**
-	 * @return the full path name of the file system access worker subprocess's
-	 *         implementation JAR
-	 */
-	public abstract String getServerWorkerJar();
-
-	/**
-	 * @param javaBinary
-	 *            the full path name to the Java binary to use
-	 */
-	public abstract void setJavaBinary(String javaBinary);
-
-	/**
-	 * @return the full path name to the Java binary to use
-	 */
-	public abstract String getJavaBinary();
-
-	/**
-	 * @param registryPort
-	 *            what port is the RMI registry on
-	 */
-	public abstract void setRegistryPort(int registryPort);
-
-	/**
-	 * @return what port is the RMI registry on
-	 */
-	public abstract int getRegistryPort();
-
-	/**
-	 * @param registryHost
-	 *            what host (network interface) is the RMI registry on
-	 */
-	public abstract void setRegistryHost(String registryHost);
-
-	/**
-	 * @return what host (network interface) is the RMI registry on
-	 */
-	public abstract String getRegistryHost();
-
-	/**
-	 * @param serverForkerJar
-	 *            the full path name of the impersonation engine's
-	 *            implementation JAR
-	 */
-	public abstract void setServerForkerJar(String serverForkerJar);
-
-	/**
-	 * @return the full path name of the impersonation engine's implementation
-	 *         JAR
-	 */
-	public abstract String getServerForkerJar();
-
-	/**
-	 * @param passwordFile
-	 *            the full path name of a file containing a password to use with
-	 *            sudo (or empty for none)
-	 */
-	public abstract void setPasswordFile(String passwordFile);
-
-	/**
-	 * @return the full path name of a file containing a password to use with
-	 *         sudo (or empty for none)
-	 */
-	public abstract String getPasswordFile();
-
-	/**
-	 * @param operatingLimit
-	 *            the maximum number of runs in the
-	 *            {@linkplain Status#Operating operating} state at once
-	 */
-	public abstract void setOperatingLimit(int operatingLimit);
-
-	@Override
-	void setPermittedWorkflowURIs(List<URI> permittedWorkflows);
-
-	/**
-	 * @return the full path name of the RMI registry subprocess's
-	 *         implementation JAR
-	 */
-	String getRegistryJar();
-
-	/**
-	 * @param rmiRegistryJar
-	 *            the full path name of the RMI registry subprocess's
-	 *            implementation JAR
-	 */
-	void setRegistryJar(String rmiRegistryJar);
-
-	/**
-	 * @return whether a run should generate provenance information by default
-	 */
-	boolean getGenerateProvenance();
-
-	/**
-	 * @param generateProvenance
-	 *            whether a run should generate provenance information by
-	 *            default
-	 */
-	void setGenerateProvenance(boolean generateProvenance);
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java b/server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
deleted file mode 100644
index 6007f88..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/worker/package-info.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 2013 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-/**
- * A Taverna Server back-end that works by forking off workflow executors.
- */
-package org.taverna.server.master.worker;
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/replacementscripts/executeworkflow.bat
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/replacementscripts/executeworkflow.bat b/server-webapp/src/main/replacementscripts/executeworkflow.bat
deleted file mode 100644
index c678855..0000000
--- a/server-webapp/src/main/replacementscripts/executeworkflow.bat
+++ /dev/null
@@ -1,25 +0,0 @@
-@ECHO OFF
-
-REM Taverna startup script
-
-REM distribution directory
-set TAVERNA_HOME=%~dp0
-
-REM 300 MB memory, 140 MB for classes
-set ARGS=-Xmx300m -XX:MaxPermSize=140m
-
-REM Taverna system properties
-set ARGS=%ARGS% "-Draven.profile=file:%TAVERNA_HOME%conf/current-profile.xml"
-set ARGS=%ARGS% -Djava.system.class.loader=net.sf.taverna.raven.prelauncher.BootstrapClassLoader 
-set ARGS=%ARGS% -Draven.launcher.app.main=net.sf.taverna.t2.commandline.CommandLineLauncher
-set ARGS=%ARGS% -Draven.launcher.show_splashscreen=false
-set ARGS=%ARGS% -Djava.awt.headless=true
-set ARGS=%ARGS% "-Dtaverna.startup=%TAVERNA_HOME%."
-IF NOT x%RAVEN_APPHOME%==x SET ARGS=%ARGS% "-Draven.launcher.app.home=%RAVEN_APPHOME%"
-IF NOT x%TAVERNA_RUN_ID%==x SET ARGS=%ARGS% "-Dtaverna.runid=%TAVERNA_RUN_ID%"
-IF NOT x%INTERACTION_HOST%==x SET ARGS=%ARGS% "-Dtaverna.interaction.host=%INTERACTION_HOST%"
-IF NOT x%INTERACTION_PORT%==x SET ARGS=%ARGS% "-Dtaverna.interaction.port=%INTERACTION_PORT%"
-IF NOT x%INTERACTION_WEBDAV%==x SET ARGS=%ARGS% "-Dtaverna.interaction.webdav_path=%INTERACTION_WEBDAV%"
-IF NOT x%INTERACTION_FEED%==x SET ARGS=%ARGS% "-Dtaverna.interaction.feed_path=%INTERACTION_FEED%"
-
-java %ARGS% -jar "%TAVERNA_HOME%lib\prelauncher-2.3.jar" %*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/replacementscripts/executeworkflow.sh
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/replacementscripts/executeworkflow.sh b/server-webapp/src/main/replacementscripts/executeworkflow.sh
deleted file mode 100644
index e9e1d36..0000000
--- a/server-webapp/src/main/replacementscripts/executeworkflow.sh
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/bin/sh
-
-set -e
-
-# 300 MB memory, 140 MB for classes
-memlimit=-Xmx300m
-permsize=-XX:MaxPermSize=140m
-
-## Parse the command line to extract the pieces to move around to before or
-## after the JAR filename...
-pre=-Djava.awt.headless=true 
-post=
-for arg
-do
-    case $arg in
-	-JXmx*) memlimit=`echo $arg | sed 's/-JX/-X/'` ;;
-	-JXX:MaxPermSize=*) permsize=`echo $arg | sed 's/-JXX/-XX/'` ;;
-	-J*) pre="$pre `echo $arg | sed 's/-J/-/'`" ;;
-	-D*) pre="$pre $arg" ;;
-	*) post="$post \"$arg\"" ;;
-    esac
-done
-if test "xx" = "x${post}x"; then
-    echo "Missing arguments! Bug in argument processing?" >&2
-    exit 1
-fi
-eval set x $post
-shift
-
-## resolve links - $0 may be a symlink
-prog="$0"
-
-real_path() {
-    readlink -m "$1" 2>/dev/null || python -c 'import os,sys;print os.path.realpath(sys.argv[1])' "$1"
-}
-
-realprog=`real_path "$prog"`
-taverna_home=`dirname "$realprog"`
-javabin=java
-if test -x "$JAVA_HOME/bin/java"; then
-    javabin="$JAVA_HOME/bin/java"
-fi
-APPHOME_PROP= 
-if test x != "x$TAVERNA_APPHOME"; then
-    APPHOME_PROP="-Dtaverna.app.home=$TAVERNA_APPHOME"
-fi
-RUNID_PROP= 
-if test x != "x$TAVERNA_RUN_ID"; then
-    RUNID_PROP="-Dtaverna.runid=$TAVERNA_RUN_ID"
-fi
-INTERACTION_PROPS=-Dtaverna.interaction.ignore_requests=true
-if test x != "x$INTERACTION_HOST"; then
-    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.host=$INTERACTION_HOST"
-    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.port=$INTERACTION_PORT"
-    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.webdav_path=$INTERACTION_WEBDAV"
-    INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.feed_path=$INTERACTION_FEED"
-    if test x != "x$INTERACTION_PUBLISH"; then
-    	INTERACTION_PROPS="$INTERACTION_PROPS -Dtaverna.interaction.publishAddressOverride=$INTERACTION_PUBLISH"
-    fi
-fi
-
-MainClass=net.sf.taverna.t2.commandline.CommandLineLauncher
-
-echo "pid:$$"
-exec "$javabin" $memlimit $permsize \
-  "-Dlog4j.configuration=file://$taverna_home/conf/log4j.properties " \
-  "-Djava.util.logging.config.file=$taverna_home/conf/logging.properties " \
-  "-Dtaverna.app.startup=$taverna_home" -Dtaverna.interaction.ignore_requests=true \
-  $APPHOME_PROP $RUNID_PROP $INTERACTION_PROPS -Djava.awt.headless=true \
-  -Dcom.sun.net.ssl.enableECC=false -Djsse.enableSNIExtension=false $pre \
-  -jar "$taverna_home/lib/taverna-command-line-0.1.1.jar" \
-  ${1+"$@"}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/admin.html
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/admin.html b/server-webapp/src/main/resources/admin.html
deleted file mode 100644
index a80a783..0000000
--- a/server-webapp/src/main/resources/admin.html
+++ /dev/null
@@ -1,240 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-<title>Taverna Server ${project.version} Administration Interface</title>
-<link id="admin" href="admin" />
-<script type="text/javascript" src="admin/static/jquery-1.8.0.min.js"></script>
-<script type="text/javascript" src="admin/static/jquery-ui-1.8.23.custom.min.js"></script>
-<script type="text/javascript" src="admin/static/admin.js"></script>
-<link href="admin/static/jquery-ui-1.8.23.custom.css" rel="stylesheet" type="text/css" />
-
-</head>
-<body>
-<img height="70" style="float:left" src="admin/static/t2cogs.png">
-<h1>Taverna Server ${project.version} Administration Interface</h1>
-<br clear="left"/>
-<div id="body">
-<ul>
-  <li><a href="#t-global">Global Settings</a></li>
-  <li><a href="#t-users">Users</a></li>
-  <li><a href="#t-workflows">Workflows</a></li>
-  <li><a href="#t-usage">Usage Records</a></li>
-  <li><a href="#t-worker">Local Worker Configuration</a></li>
-</ul>
-  
-<div id="t-global">
-<label title="The number of invocations of the main interface webapp that have been done. Be aware that one service call can result in many invocations due to resource resolution." for="invokationCount">Invocation Count:</label>
-<span title="The number of invocations of the main interface webapp that have been done. Be aware that one service call can result in many invocations due to resource resolution." id="invokationCount">0</span>
-<br>
-<label title="The number of runs that currently exist." for="runCount">Run Count:</label>
-<span title="The number of runs that currently exist." id="runCount">0</span>
-<br>
-<label title="The number of runs that are currently operating." for="operatingCount">Operating Run Count:</label>
-<span title="The number of runs that are currently operating." id="operatingCount">0</span>
-<br>
-<label title="Whether workflow runs should create provenance traces by default. Users can explicitly override this." for="generateProvenance">Generate Provenance by Default</label>
-<input type="checkbox" id="generateProvenance" />
-<br>
-<label title="The time it took for the back-end engine to start up, in seconds. Should usually be short." for="startupTime">Back-End Startup Time (seconds):</label>
-<span title="The time it took for the back-end engine to start up, in seconds. Should usually be short." id="startupTime">0</span>
-<br>
-<label title="The exit code from the last time the back-end was shut down. Blank if the back end has never been shut down while the current webapp instance is running (i.e., since the last boot of the container)." for="lastExitCode">Back-End Last Exit Code:</label>
-<span title="The exit code from the last time the back-end was shut down. Blank if the back end has never been shut down while the current webapp instance is running (i.e., since the last boot of the container)." id="lastExitCode"></span>
-<p>
-<label title="Whether new workflow runs should be created. Disabling this does not prevent existing runs from executing." for="allowNew">Allow New Runs</label>
-<input type="checkbox" id="allowNew" />
-<label title="Whether to record the workflows being run by users. Very noisy due to length of workflow documents, occasionally useful." for="logWorkflows">Log Executed Workflows</label>
-<input type="checkbox" id="logWorkflows" />
-<label title="Whether to record exceptions generated by users in the code (as well as converting them to faults and error responses). Useful for debugging, but noisy." for="logFaults">Log User Exceptions</label>
-<input type="checkbox" id="logFaults" />
-<p>
-<label title="The maximum number of workflow runs that can exist at once, in any state." for="runLimit">Maximum Simultaneous Existing Workflow Runs</label>
-<input title="The maximum number of workflow runs that can exist at once, in any state." id="runLimit" size="3" />
-<br>
-<label title="The maximum number of workflow runs that can be executing at once." for="operatingLimit">Maximum Simultaneous Executing Workflow Runs</label>
-<input title="The maximum number of workflow runs that can be executing at once." id="operatingLimit" size="3" />
-<br>
-<label title="How long to allow a workflow to execute for by default (clients can change this), in minutes." for="defaultLifetime">Default Run Lifetime (minutes)</label>
-<input title="How long to allow a workflow to execute for by default (clients can change this), in minutes." id="defaultLifetime" size="7" />
-</div><!-- t-global -->
-
-<div id="t-users">
-<table id="userList">
-  <tr><th>Username<th>System Username</tr>
-</table>
-<h3>Add a user</h3>
-<table border=1>
-  <tr>
-    <td><label title="The user name to create." for="newUsername">Username</label>
-    <td><input title="The user name to create." size=12 id="newUsername" />
-  </tr>
-  <tr>
-    <td><label title="The password to use for the user." for="newPassword">Password</label>
-    <td><input title="The password to use for the user." size=12 id="newPassword" type="password"/>
-  </tr>
-  <tr>
-    <td><label title="The system account to run the user's workflows in; leave blank for the default." for="newSysID">System ID</label>
-    <td><input title="The system account to run the user's workflows in; leave blank for the default." size=12 id="newSysID" />
-  </tr>
-  <tr><td colspan=2>
-    <label title="Whether to allow this user to log in at all." for="newEnabled">Enabled</label>
-    <input type="checkbox" id="newEnabled" />
-    <label title="Whether the user has administrative privileges (can see all workflow runs, can access the administration page)." for="newAdmin">Admin</label>
-    <input type="checkbox" id="newAdmin" />
-  </td></tr>
-  <tr><td colspan=2>
-    <button id="makeNewUser">Create a new user</button>
-  </td></tr>
-</table>
-</div><!-- t-users -->
-
-<div id="t-workflows">
-<label title="Workflow URIs to limit execution to." for="workflows">Workflow URIs (one per line)</label>
-<br>
-<textarea title="Workflow URIs to limit execution to." rows="5" cols="60" id="workflows"></textarea>
-<p>
-<button id="saveWorkflows">Save</button> <button id="refreshWorkflows">Refresh</button> <button id="emptyWorkflows">Empty URIs list</button>
-</div>
-
-<div id="t-usage">
-Download <a href="#" id="ur">usage records</a> (warning: may be slow!)
-<p>
-<label title="The name of a file to write usage records to. Note that this file will end up containing many XML documents concatenated together; it is up to you to split them up as necessary. Each record is only written as it is generated; this does not produce historic data." for="usageRecordDumpFile">Usage Record Dump File</label>
-<input title="The name of a file to write usage records to. Note that this file will end up containing many XML documents concatenated together; it is up to you to split them up as necessary. Each record is only written as it is generated; this does not produce historic data." id="usageRecordDumpFile" size="50" />
-</div><!-- t-usage -->
-
-<div id="t-worker">
-  <div id="a-worker">
-
-    <h3><a href="#">Subprocess Implementation Control</a></h3>
-    <div>
-      <table>
-	<tr>
-	  <td> <label title="The full path of the Java executable to use. Normally set correct by default." for="javaBinary">Java Executable (for subprocesses):</label> </td>
-	  <td> <input title="The full path of the Java executable to use. Normally set correct by default." id="javaBinary" size="80" /> </td>
-	</tr>
-	<tr>
-	  <td> <label title="The full path of the secure subprocess fork engine to use. Normally set correct by default." for="serverForkerJar">Subprocess Factory JAR:</label> </td>
-	  <td> <input title="The full path of the secure subprocess fork engine to use. Normally set correct by default." id="serverForkerJar" size="80" /> </td>
-	</tr>
-	<tr>
-	  <td> <label title="The full path of a file containing the credentials to use with sudo. Leave blank to use a password-less connection (see documentation for how to configure)." for="runasPasswordFile">File with password for sudo:</label> </td>
-	  <td> <input title="The full path of a file containing the credentials to use with sudo. Leave blank to use a password-less connection (see documentation for how to configure)." id="runasPasswordFile" size="80" /> </td>
-	</tr>
-	<tr>
-	  <td> <label title="The full path of the user filesystem access and workflow initiation engine to use. Normally set correct by default." for="serverWorkerJar">User Filesystem Access JAR:</label> </td>
-	  <td> <input title="The full path of the user filesystem access and workflow initiation engine to use. Normally set correct by default." id="serverWorkerJar" size="80" /> </td>
-	</tr>
-	<tr>
-	  <td> <label title="The full path of the workflow engine executable. Normally set correctly by default." for="executeWorkflowScript">Workflow Engine Executable:</label> </td>
-	  <td> <input title="The full path of the workflow engine executable. Normally set correctly by default." id="executeWorkflowScript" size="80" /> </td>
-	</tr>
-      </table>
-    </div>
-
-    <h3><a href="#">Worker Registration Control</a></h3>
-    <div>
-      <label title="The machine hosting the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryHost">Registry Host</label>
-      <input title="The machine hosting the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryHost" size="20" />
-      <label title="The port number the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryPort">Port</label>
-      <input title="The port number the RMI registry. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryPort" size="5" />
-      <br>
-      <label title="The full path of the RMI registry implementation JAR file. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" for="registryJar">RMI Registry JAR</label>
-      <input title="The full path of the RMI registry implementation JAR file. WARNING: changing this will probably break your configuration! Contact the myGrid team for help before adjusting!" id="registryJar" size="80" />
-      <br>
-      <label title="The time to wait (in seconds) for the back-end processes to boot and register themselves with the RMI registry. Busy machines may need a longer value here." for="registrationWaitSeconds">Time to wait for registration (seconds)</label>
-      <input title="The time to wait (in seconds) for the back-end processes to boot and register themselves with the RMI registry. Busy machines may need a longer value here." id="registrationWaitSeconds" size="5" />
-      <br>
-      <label title="How long to wait (in milliseconds) between probes to the registry to detect the registration of a back-end process." for="registrationPollMillis">Time to wait between polling to
-      detect registration (milliseconds)</label>
-      <input title="How long to wait (in milliseconds) between probes to the registry to detect the registration of a back-end process." id="registrationPollMillis" size="5" />
-    </div>
-
-    <h3><a href="#">System User/Factory ID Mapping</a></h3>
-    <div>
-      <table title="The mapping of system user IDs to factory identifiers (used in the RMI registry). Note that this is read-only." id="factoryProcessMapping" border="1">
-      </table>
-    </div>
-
-   	<h3><a href="#">Extra Workflow Engine Configuration</a></h3>
-   	<div>
-   		<h4>System Properties</h4>
-   		<table id="extraArguments-prop">
-   		<tr><td></td><td><button title="Add a system property to pass to the back-end engine." id="extra-prop-add">Add System Property</button></td></tr>
-   		</table>
-   		<h4>Environment Variables</h4>
-   		<table id="extraArguments-env">
-   		<tr><td></td><td><button title="Add an environment variable to pass to the back-end engine." id="extra-env-add">Add Environment Variable</button></td></tr>
-   		</table>
-   		<h4>Java Runtime Configuration</h4>
-   		<table id="extraArguments-runtime">
-   		<tr><td></td><td><button title="Add a Java runtime parameter (e.g., Xmx=400m to set the memory usage limit to 400MB) to pass to the back-end engine. Note the lack of a leading '-' character!" id="extra-run-add">Add Runtime Configuration</button></td></tr>
-   		</table>
-   	</div>
-
-  </div><!-- a-worker -->
-</div><!-- t-worker -->
-
-</div>
-
-<hr>
-<address>Donal Fellows / University of Manchester</address>
-
-<!-- DIALOG BOXES -->
-<div id="dialog-confirm" title="Delete user?" style="display: none">
-  <p>
-  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
-  This user will be permanently deleted from the system. Are you sure?
-  </p>
-</div>
-
-<div id="dialog-password" title="Change password?" style="display: none">
-  <p>
-  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
-  This will permanently change the user's password. Make sure you wish
-  to do this.
-  </p>
-  <p>
-  <input title="New password" id="change-password" type="password" size="12" />
-  <br>
-  Please repeat it to be sure...
-  <br>
-  <input title="New password (again)" id="change-password2" type="password" size="12" />
-  </p>
-</div>
-
-<div id="dialog-environment" title="Set environment variable?" style="display: none">
-  <p>
-  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
-  Set an environment variable to be passed to the workflow engine.
-  </p>
-  <p>
-  <input title="Environment variable name" id="env-key" size="15" /> =
-  <input title="Environment variable value" id="env-value" size="20" />
-  </p>
-</div>
-
-<div id="dialog-runtime" title="Set runtime configuration?" style="display: none">
-  <p>
-  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
-  Set a runtime parameter (e.g., -Xmx400m for a 400MB memory limit) for the Java runtime.
-  </p>
-  <p>
-  <input title="Java runtime configuration parameter" id="runtime-value" size="20" />
-  </p>
-</div>
-
-<div id="dialog-property" title="Set runtime property?" style="display: none">
-  <p>
-  <span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
-  Set a configuration property for the Java runtime.
-  </p>
-  <p>
-  <input title="System property name" id="prop-key" size="15" /> =
-  <input title="System property value" id="prop-value" size="20" />
-  </p>
-</div>
-
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/capabilities.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/capabilities.properties b/server-webapp/src/main/resources/capabilities.properties
deleted file mode 100644
index 2b4844f..0000000
--- a/server-webapp/src/main/resources/capabilities.properties
+++ /dev/null
@@ -1,38 +0,0 @@
-# This is currently a hand-curated list. This sucks! 
-
-######## --- PLATFORM --- ########
-http\://ns.taverna.org.uk/2013/software/taverna = 2.5
-
-######## --- OUTPUTS/PROVENANCE --- ########
-http\://ns.taverna.org.uk/2013/bundle/run = 1.0
-http\://ns.taverna.org.uk/2013/provenance/prov = 1.0
-
-######## --- ACTIVITIES --- ########
-http\://ns.taverna.org.uk/2010/activity/nested-workflow = 1.5
-http\://ns.taverna.org.uk/2010/activity/apiconsumer = 1.5
-http\://ns.taverna.org.uk/2010/activity/beanshell = 1.5
-http\://ns.taverna.org.uk/2010/activity/localworker = 1.5
-http\://ns.taverna.org.uk/2010/activity/biomart = 1.5
-http\://ns.taverna.org.uk/2010/activity/biomoby/object = 1.5
-http\://ns.taverna.org.uk/2010/activity/biomoby/service = 1.5
-http\://ns.taverna.org.uk/2010/activity/rshell = 1.5
-http\://ns.taverna.org.uk/2010/activity/soaplab = 1.5
-http\://ns.taverna.org.uk/2010/activity/spreadsheet-import = 1.5
-http\://ns.taverna.org.uk/2010/activity/constant = 1.5
-http\://ns.taverna.org.uk/2010/activity/component = 1.5
-http\://ns.taverna.org.uk/2010/activity/wsdl = 1.5
-http\://ns.taverna.org.uk/2010/activity/wsdl/xml-splitter/in = 1.5
-http\://ns.taverna.org.uk/2010/activity/wsdl/xml-splitter/out = 1.5
-http\://ns.taverna.org.uk/2010/activity/tool = 1.5
-http\://ns.taverna.org.uk/2010/activity/rest = 1.5
-http\://ns.taverna.org.uk/2010/activity/xpath = 1.5
-http\://ns.taverna.org.uk/2010/activity/webdav = 1.5
-http\://ns.taverna.org.uk/2010/activity/interaction = 1.5
-
-######## --- DISPATCH LAYERS --- ########
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/ErrorBounce = 1.5
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Failover = 1.5
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Invoke = 1.5
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Loop = 1.5
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Parallelize = 1.5
-http\://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Retry = 1.5
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/log4j.properties b/server-webapp/src/main/resources/log4j.properties
deleted file mode 100644
index ea0ea12..0000000
--- a/server-webapp/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,39 +0,0 @@
-log4j.rootLogger=info, R
-log4j.category.DataNucleus.Query=warn
-#log4j.category.DataNucleus.Datastore.Schema=debug
-#log4j.logger.org.springframework.security=DEBUG
-#log4j.category.Taverna=debug
-
-log4j.appender.R=org.apache.log4j.RollingFileAppender
-log4j.appender.R.File=${catalina.home}/logs/tavserv.out
-log4j.appender.R.MaxFileSize=10MB
-log4j.appender.R.MaxBackupIndex=30
-log4j.appender.R.layout=org.apache.log4j.PatternLayout
-log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
-
-#log4j.category.Taverna=INFO, A1
-#log4j.category.Taverna.Server.LocalWorker.RunDB=INFO
-#log4j.category.Taverna.Server.Webapp=INFO
-#log4j.category.Taverna.Server.LocalWorker.Policy=INFO
-#log4j.category.Taverna.Server.LocalWorker.Security=INFO
-## Swallow Derby's messages
-#log4j.category.Derby=WARN, B2
-## Will you _shut up_, DataNucleus! <hits with rolled-up newspaper>
-#log4j.category.DataNucleus=WARN, B2
-##log4j.category.DataNucleus.SchemaTool=DEBUG
-##log4j.category.DataNucleus.Datastore.Schema=DEBUG
-##log4j.category.DataNucleus.Datastore.Native=DEBUG
-##log4j.logger.org.springframework.security=DEBUG, B2
-#log4j.category.org.springframework=INFO, B2
-#log4j.category.org.apache.cxf=INFO, B2
-#log4j.category.org.apache.cxf.jaxrs.utils.JAXRSUtils=INFO
-#log4j.category.eu.medsea=INFO, B2
-#log4j.category.org.apache.axiom=INFO, B2
-## Appender for Taverna Server components
-#log4j.appender.A1=org.apache.log4j.ConsoleAppender
-#log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-#log4j.appender.A1.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
-## Appender for Framework components
-#log4j.appender.B2=org.apache.log4j.ConsoleAppender
-#log4j.appender.B2.layout=org.apache.log4j.PatternLayout
-#log4j.appender.B2.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} - %m%n

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/security.policy
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/security.policy b/server-webapp/src/main/resources/security.policy
deleted file mode 100644
index 1ec4166..0000000
--- a/server-webapp/src/main/resources/security.policy
+++ /dev/null
@@ -1,3 +0,0 @@
-grant {
-   permission java.security.AllPermission "*:*";
-};


[45/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
----------------------------------------------------------------------
diff --git a/server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java b/server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
deleted file mode 100644
index d12d3d8..0000000
--- a/server-usagerecord/src/main/java/org/ogf/usage/JobUsageRecord.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2011 The University of Manchester
- * 
- * See the file "LICENSE" for license terms.
- */
-package org.ogf.usage;
-
-import static java.util.UUID.randomUUID;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.math.BigInteger;
-import java.util.Date;
-import java.util.GregorianCalendar;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlTransient;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.datatype.DatatypeFactory;
-import javax.xml.transform.dom.DOMSource;
-
-import org.ogf.usage.v1_0.Charge;
-import org.ogf.usage.v1_0.ConsumableResourceType;
-import org.ogf.usage.v1_0.CpuDuration;
-import org.ogf.usage.v1_0.Disk;
-import org.ogf.usage.v1_0.EndTime;
-import org.ogf.usage.v1_0.Host;
-import org.ogf.usage.v1_0.JobName;
-import org.ogf.usage.v1_0.MachineName;
-import org.ogf.usage.v1_0.Memory;
-import org.ogf.usage.v1_0.Network;
-import org.ogf.usage.v1_0.NodeCount;
-import org.ogf.usage.v1_0.Processors;
-import org.ogf.usage.v1_0.ProjectName;
-import org.ogf.usage.v1_0.Queue;
-import org.ogf.usage.v1_0.RecordIdentity;
-import org.ogf.usage.v1_0.ResourceType;
-import org.ogf.usage.v1_0.ServiceLevel;
-import org.ogf.usage.v1_0.StartTime;
-import org.ogf.usage.v1_0.Status;
-import org.ogf.usage.v1_0.SubmitHost;
-import org.ogf.usage.v1_0.Swap;
-import org.ogf.usage.v1_0.TimeDuration;
-import org.ogf.usage.v1_0.TimeInstant;
-import org.ogf.usage.v1_0.UserIdentity;
-import org.ogf.usage.v1_0.WallDuration;
-import org.w3c.dom.Element;
-
-@XmlRootElement(name = "UsageRecord", namespace = "http://schema.ogf.org/urf/2003/09/urf")
-public class JobUsageRecord extends org.ogf.usage.v1_0.UsageRecordType {
-	/**
-	 * Create a new usage record with a random UUID as its identity.
-	 * 
-	 * @throws DatatypeConfigurationException
-	 *             If the factory for XML-relevant datatypes fails to build; not
-	 *             expected.
-	 */
-	public JobUsageRecord() throws DatatypeConfigurationException {
-		datatypeFactory = DatatypeFactory.newInstance();
-		RecordIdentity recid = new RecordIdentity();
-		recid.setRecordId(randomUUID().toString());
-		recid.setCreateTime(datatypeFactory
-				.newXMLGregorianCalendar(new GregorianCalendar()));
-		setRecordIdentity(recid);
-	}
-
-	/**
-	 * Create a new usage record with a random UUID as its identity.
-	 * 
-	 * @param name
-	 *            The name of the job to which this record pertains.
-	 * @throws DatatypeConfigurationException
-	 *             If the factory for XML-relevant datatypes fails to build; not
-	 *             expected.
-	 */
-	public JobUsageRecord(String name) throws DatatypeConfigurationException {
-		this();
-		setJobName(name);
-	}
-
-	@XmlTransient
-	private DatatypeFactory datatypeFactory;
-
-	public Status setStatus(String status) {
-		Status s = new Status();
-		s.setValue(status);
-		setStatus(s);
-		return s;
-	}
-
-	public WallDuration addWallDuration(long millis) {
-		WallDuration wall = new WallDuration();
-		wall.setValue(datatypeFactory.newDuration(millis));
-		getWallDurationOrCpuDurationOrNodeCount().add(wall);
-		return wall;
-	}
-
-	public CpuDuration addCpuDuration(long millis) {
-		CpuDuration cpu = new CpuDuration();
-		cpu.setValue(datatypeFactory.newDuration(millis));
-		getWallDurationOrCpuDurationOrNodeCount().add(cpu);
-		return cpu;
-	}
-
-	public NodeCount addNodeCount(int nodes) {
-		NodeCount nc = new NodeCount();
-		nc.setValue(BigInteger.valueOf(nodes));
-		getWallDurationOrCpuDurationOrNodeCount().add(nc);
-		return nc;
-	}
-
-	public Processors addProcessors(int processors) {
-		Processors pc = new Processors();
-		pc.setValue(BigInteger.valueOf(processors));
-		getWallDurationOrCpuDurationOrNodeCount().add(pc);
-		return pc;
-	}
-
-	public SubmitHost addSubmitHost(String host) {
-		SubmitHost sh = new SubmitHost();
-		sh.setValue(host);
-		getWallDurationOrCpuDurationOrNodeCount().add(sh);
-		return sh;
-	}
-
-	public Host addHost(String host) {
-		Host h = new Host();
-		h.setValue(host);
-		getWallDurationOrCpuDurationOrNodeCount().add(h);
-		return h;
-	}
-
-	public MachineName addMachine(String host) {
-		MachineName machine = new MachineName();
-		machine.setValue(host);
-		getWallDurationOrCpuDurationOrNodeCount().add(machine);
-		return machine;
-	}
-
-	public ProjectName addProject(String project) {
-		ProjectName p = new ProjectName();
-		p.setValue(project);
-		getWallDurationOrCpuDurationOrNodeCount().add(p);
-		return p;
-	}
-
-	public void addStartAndEnd(Date start, Date end) {
-		GregorianCalendar gc;
-
-		gc = new GregorianCalendar();
-		gc.setTime(start);
-		StartTime st = new StartTime();
-		st.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
-		getWallDurationOrCpuDurationOrNodeCount().add(st);
-
-		gc = new GregorianCalendar();
-		gc.setTime(end);
-		EndTime et = new EndTime();
-		et.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
-		getWallDurationOrCpuDurationOrNodeCount().add(et);
-	}
-
-	public Queue addQueue(String queue) {
-		Queue q = new Queue();
-		q.setValue(queue);
-		getWallDurationOrCpuDurationOrNodeCount().add(q);
-		return q;
-	}
-
-	public void addResource(ConsumableResourceType consumable) {
-		getWallDurationOrCpuDurationOrNodeCount().add(consumable);
-	}
-
-	public ResourceType addResource(ResourceType resource) {
-		getWallDurationOrCpuDurationOrNodeCount().add(resource);
-		return resource;
-	}
-
-	public ResourceType addResource(String description, String value) {
-		ResourceType resource = new ResourceType();
-		resource.setDescription(description);
-		resource.setValue(value);
-		getWallDurationOrCpuDurationOrNodeCount().add(resource);
-		return resource;
-	}
-
-	public ServiceLevel addServiceLevel(String service) {
-		ServiceLevel sl = new ServiceLevel();
-		sl.setValue(service);
-		getDiskOrMemoryOrSwap().add(sl);
-		return sl;
-	}
-
-	public Memory addMemory(long memory) {
-		Memory mem = new Memory();
-		mem.setValue(BigInteger.valueOf(memory));
-		getDiskOrMemoryOrSwap().add(mem);
-		return mem;
-	}
-
-	public TimeInstant addTimestamp(Date timestamp, String type) {
-		TimeInstant instant = new TimeInstant();
-		GregorianCalendar gc = new GregorianCalendar();
-		gc.setTime(timestamp);
-		instant.setValue(datatypeFactory.newXMLGregorianCalendar(gc));
-		instant.setType(type);
-		getDiskOrMemoryOrSwap().add(instant);
-		return instant;
-	}
-
-	public TimeDuration addDuration(long millis, String type) {
-		TimeDuration duration = new TimeDuration();
-		duration.setValue(datatypeFactory.newDuration(millis));
-		duration.setType(type);
-		getDiskOrMemoryOrSwap().add(duration);
-		return duration;
-	}
-
-	public Network addNetwork(long value) {
-		Network net = new Network();
-		net.setValue(BigInteger.valueOf(value));
-		getDiskOrMemoryOrSwap().add(net);
-		return net;
-	}
-
-	public Disk addDisk(long value) {
-		Disk disk = new Disk();
-		disk.setValue(BigInteger.valueOf(value));
-		getDiskOrMemoryOrSwap().add(disk);
-		return disk;
-	}
-
-	public Swap addSwap(long value) {
-		Swap net = new Swap();
-		net.setValue(BigInteger.valueOf(value));
-		getDiskOrMemoryOrSwap().add(net);
-		return net;
-	}
-
-	public UserIdentity addUser(String localUID, String globalName) {
-		UserIdentity user = new UserIdentity();
-		user.setLocalUserId(localUID);
-		user.setGlobalUserName(globalName);
-		getUserIdentity().add(user);
-		return user;
-	}
-
-	public JobName setJobName(String name) {
-		JobName jn = new JobName();
-		jn.setValue(name);
-		this.setJobName(jn);
-		return jn;
-	}
-
-	public Charge addCharge(float value) {
-		Charge c = new Charge();
-		c.setValue(value);
-		this.setCharge(c);
-		return c;
-	}
-
-	@SuppressWarnings("unchecked")
-	public <T> T getOfType(Class<T> clazz) {
-		for (Object o : getWallDurationOrCpuDurationOrNodeCount())
-			if (clazz.isInstance(o))
-				return (T) o;
-		for (Object o : getDiskOrMemoryOrSwap())
-			if (clazz.isInstance(o))
-				return (T) o;
-		return null;
-	}
-
-	public String marshal() throws JAXBException {
-		StringWriter writer = new StringWriter();
-		JAXBContext.newInstance(getClass()).createMarshaller()
-				.marshal(this, writer);
-		return writer.toString();
-	}
-
-	private static JAXBContext context;
-	static {
-		try {
-			context = JAXBContext.newInstance(JobUsageRecord.class);
-		} catch (JAXBException e) {
-			throw new RuntimeException("failed to handle JAXB annotated class",
-					e);
-		}
-	}
-
-	public static JobUsageRecord unmarshal(String s) throws JAXBException {
-		return (JobUsageRecord) context.createUnmarshaller().unmarshal(
-				new StringReader(s));
-	}
-
-	public static JobUsageRecord unmarshal(Element elem) throws JAXBException {
-		return context.createUnmarshaller()
-				.unmarshal(new DOMSource(elem), JobUsageRecord.class)
-				.getValue();
-	}
-
-	// TODO: Add signing support
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/src/main/xsd/ur.xsd
----------------------------------------------------------------------
diff --git a/server-usagerecord/src/main/xsd/ur.xsd b/server-usagerecord/src/main/xsd/ur.xsd
deleted file mode 100644
index 16344a7..0000000
--- a/server-usagerecord/src/main/xsd/ur.xsd
+++ /dev/null
@@ -1,425 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xsd:schema attributeFormDefault="qualified" jaxb:version="2.1"
-	elementFormDefault="qualified" targetNamespace="http://schema.ogf.org/urf/2003/09/urf"
-	xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:urf="http://schema.ogf.org/urf/2003/09/urf"
-	xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
-	xsi:schemaLocation="http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd">
-	<xsd:annotation>
-		<!-- Copyright (c) 2003-2008 Open Grid Forum -->
-		<xsd:documentation xml:lang="en">Usage Record Working Group XML Schema definition</xsd:documentation>
-		<xsd:appinfo>
-			<jaxb:schemaBindings>
-				<jaxb:package name="org.ogf.usage.v1_0" />
-			</jaxb:schemaBindings>
-		</xsd:appinfo>
-	</xsd:annotation>
-	<xsd:import namespace="http://www.w3.org/2000/09/xmldsig#"
-		schemaLocation="xmlds.xsd" /> <!-- http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd -->
-	<xsd:complexType name="UsageRecordType">
-		<xsd:sequence>
-			<xsd:element ref="urf:RecordIdentity" />
-			<xsd:element minOccurs="0" ref="urf:JobIdentity" />
-			<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:UserIdentity" />
-			<xsd:element minOccurs="0" ref="urf:JobName" />
-			<xsd:element minOccurs="0" ref="urf:Charge" />
-			<xsd:element ref="urf:Status" />
-			<xsd:choice maxOccurs="unbounded" minOccurs="0">
-				<xsd:annotation>
-					<xsd:documentation>
-						The elements grouped together in this choice may be represented
-						within a usage record multiple times. Each of these appearances
-						must be differentiated by the metric and/or type associated with
-						the element.
-					</xsd:documentation>
-				</xsd:annotation>
-				<xsd:element ref="urf:Disk" />
-				<xsd:element ref="urf:Memory" />
-				<xsd:element ref="urf:Swap" />
-				<xsd:element ref="urf:Network" />
-				<xsd:element ref="urf:TimeDuration" />
-				<xsd:element ref="urf:TimeInstant" />
-				<xsd:element ref="urf:ServiceLevel" />
-			</xsd:choice>
-			<xsd:choice maxOccurs="unbounded" minOccurs="0">
-				<xsd:element minOccurs="0" ref="urf:WallDuration" />
-				<xsd:sequence minOccurs="0">
-					<xsd:element maxOccurs="2" minOccurs="0" ref="urf:CpuDuration" />
-				</xsd:sequence>
-				<xsd:element minOccurs="0" ref="urf:NodeCount" />
-				<xsd:element minOccurs="0" ref="urf:Processors" />
-				<xsd:element minOccurs="0" ref="urf:EndTime" />
-				<xsd:element minOccurs="0" ref="urf:StartTime" />
-				<xsd:element minOccurs="0" ref="urf:MachineName" />
-				<xsd:element minOccurs="0" ref="urf:SubmitHost" />
-				<xsd:element minOccurs="0" ref="urf:Queue" />
-				<xsd:sequence minOccurs="0">
-					<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:ProjectName" />
-				</xsd:sequence>
-				<xsd:sequence minOccurs="0">
-					<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:Host" />
-				</xsd:sequence>
-				<xsd:sequence minOccurs="0">
-					<xsd:choice maxOccurs="unbounded" minOccurs="0">
-						<xsd:element ref="urf:PhaseResource" />
-						<xsd:element ref="urf:VolumeResource" />
-						<xsd:element ref="urf:Resource" />
-						<xsd:element ref="urf:ConsumableResource" />
-					</xsd:choice>
-				</xsd:sequence>
-			</xsd:choice>
-		</xsd:sequence>
-	</xsd:complexType>
-	<xsd:element abstract="true" name="Usage" type="urf:UsageRecordType" />
-	<xsd:element name="UsageRecord" substitutionGroup="urf:Usage"
-		type="urf:UsageRecordType" />
-	<xsd:element name="JobUsageRecord" substitutionGroup="urf:Usage">
-		<xsd:complexType>
-			<xsd:complexContent>
-				<xsd:extension base="urf:UsageRecordType" />
-			</xsd:complexContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="UsageRecords">
-		<xsd:complexType>
-			<xsd:sequence>
-				<xsd:element maxOccurs="unbounded" minOccurs="0" ref="urf:Usage" />
-			</xsd:sequence>
-		</xsd:complexType>
-	</xsd:element>
-	<!-- Common properties that may be measured with several different metrics 
-		within the same usage record -->
-	<xsd:element name="Network">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attributeGroup ref="urf:intervallicVolume" />
-					<xsd:attribute default="total" ref="urf:metric" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Disk">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attributeGroup ref="urf:intervallicVolume" />
-					<xsd:attribute default="total" ref="urf:metric" use="optional" />
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Memory">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attributeGroup ref="urf:intervallicVolume" />
-					<xsd:attribute default="total" ref="urf:metric" use="optional" />
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Swap">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attributeGroup ref="urf:intervallicVolume" />
-					<xsd:attribute default="total" ref="urf:metric" use="optional" />
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="NodeCount">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attribute default="total" ref="urf:metric" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Processors">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:positiveInteger">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attribute ref="urf:metric" use="optional" />
-					<xsd:attribute name="consumptionRate" type="xsd:float"
-						use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="TimeDuration">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:duration">
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="TimeInstant">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:dateTime">
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="ServiceLevel">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:token">
-					<xsd:attribute ref="urf:type" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<!-- This element should appear at most twice within a usage record, with 
-		differing values for usageType for each appearance -->
-	<xsd:element name="CpuDuration">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:duration">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attribute name="usageType">
-						<xsd:simpleType>
-							<xsd:restriction base="xsd:token">
-								<xsd:enumeration value="user" />
-								<xsd:enumeration value="system" />
-							</xsd:restriction>
-						</xsd:simpleType>
-					</xsd:attribute>
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<!-- These common properties should appear at most once within a usage record, 
-		rather that at most once per metric per usage record -->
-	<xsd:element name="WallDuration">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:duration">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="EndTime">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:dateTime">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="StartTime">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:dateTime">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="MachineName">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="urf:domainNameType">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="SubmitHost">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="urf:domainNameType">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Host">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="urf:domainNameType">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attribute default="false" name="primary" type="xsd:boolean" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Queue">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:string">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="JobName">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:string">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="ProjectName">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:string">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Status">
-		<xsd:annotation>
-			<xsd:documentation>
-				Minimum required set = {Aborted, Completed, Failed,
-				Held, Queued, Started, Suspended}
-			</xsd:documentation>
-		</xsd:annotation>
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:token">
-					<xsd:attribute ref="urf:description" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="Charge">
-		<xsd:complexType>
-			<xsd:simpleContent>
-				<xsd:extension base="xsd:float">
-					<xsd:attribute ref="urf:description" use="optional" />
-					<xsd:attribute ref="urf:unit" use="optional" />
-					<xsd:attribute name="formula" type="xsd:string" use="optional" />
-				</xsd:extension>
-			</xsd:simpleContent>
-		</xsd:complexType>
-	</xsd:element>
-	<!-- identity elements -->
-	<xsd:element name="JobIdentity">
-		<xsd:complexType>
-			<xsd:sequence>
-				<xsd:element minOccurs="0" name="GlobalJobId" type="xsd:string" />
-				<xsd:element minOccurs="0" name="LocalJobId" type="xsd:string" />
-				<xsd:sequence>
-					<xsd:element maxOccurs="unbounded" minOccurs="0"
-						name="ProcessId" type="xsd:string" />
-				</xsd:sequence>
-			</xsd:sequence>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="UserIdentity">
-		<xsd:complexType>
-			<xsd:sequence>
-				<xsd:element minOccurs="0" name="LocalUserId" type="xsd:string" />
-				<xsd:element minOccurs="0" name="GlobalUserName" type="xsd:string" />
-				<xsd:element minOccurs="0" ref="ds:KeyInfo" />
-			</xsd:sequence>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="RecordIdentity">
-		<xsd:complexType>
-			<xsd:sequence minOccurs="0">
-				<xsd:element ref="ds:KeyInfo" />
-			</xsd:sequence>
-			<xsd:attribute name="recordId" type="xsd:token" use="required" />
-			<xsd:attribute name="createTime" type="xsd:dateTime" use="optional" />
-		</xsd:complexType>
-	</xsd:element>
-	<!-- Extensibility Framework -->
-	<xsd:element name="Resource" type="urf:ResourceType" />
-	<xsd:element name="ConsumableResource" type="urf:ConsumableResourceType" />
-	<xsd:element name="PhaseResource">
-		<xsd:complexType>
-			<xsd:complexContent>
-				<xsd:extension base="urf:ConsumableResourceType">
-					<xsd:attribute ref="urf:phaseUnit" use="optional" />
-				</xsd:extension>
-			</xsd:complexContent>
-		</xsd:complexType>
-	</xsd:element>
-	<xsd:element name="VolumeResource">
-		<xsd:complexType>
-			<xsd:complexContent>
-				<xsd:extension base="urf:ConsumableResourceType">
-					<xsd:attribute ref="urf:storageUnit" use="optional" />
-				</xsd:extension>
-			</xsd:complexContent>
-		</xsd:complexType>
-	</xsd:element>
-	<!-- Create a generic consumable resource. Carries the units attribute -->
-	<xsd:complexType name="ConsumableResourceType">
-		<xsd:simpleContent>
-			<xsd:extension base="xsd:float">
-				<xsd:attribute name="units" type="xsd:string" use="optional" />
-				<xsd:attribute ref="urf:description" use="optional" />
-			</xsd:extension>
-		</xsd:simpleContent>
-	</xsd:complexType>
-	<!-- Create a generic resource type -->
-	<xsd:complexType name="ResourceType">
-		<xsd:simpleContent>
-			<xsd:extension base="xsd:string">
-				<xsd:attribute ref="urf:description" use="optional" />
-			</xsd:extension>
-		</xsd:simpleContent>
-	</xsd:complexType>
-	<!-- Global Attribute Definitions -->
-	<xsd:attribute name="description" type="xsd:string" />
-	<!-- Units of measure attribute definitions -->
-	<xsd:attribute name="unit" type="xsd:token" />
-	<xsd:attribute name="storageUnit">
-		<xsd:simpleType>
-			<xsd:restriction base="xsd:token">
-				<xsd:enumeration value="b" />
-				<xsd:enumeration value="B" />
-				<xsd:enumeration value="KB" />
-				<xsd:enumeration value="MB" />
-				<xsd:enumeration value="GB" />
-				<xsd:enumeration value="PB" />
-				<xsd:enumeration value="EB" />
-				<xsd:enumeration value="Kb" />
-				<xsd:enumeration value="Mb" />
-				<xsd:enumeration value="Gb" />
-				<xsd:enumeration value="Pb" />
-				<xsd:enumeration value="Eb" />
-			</xsd:restriction>
-		</xsd:simpleType>
-	</xsd:attribute>
-	<xsd:attribute name="phaseUnit" type="xsd:duration" />
-	<xsd:attributeGroup name="intervallicVolume">
-		<xsd:attribute ref="urf:storageUnit" use="optional" />
-		<xsd:attribute ref="urf:phaseUnit" use="optional" />
-	</xsd:attributeGroup>
-	<!-- End units attributes -->
-	<xsd:attribute name="metric" type="xsd:token" />
-	<xsd:attribute name="type" type="xsd:token" />
-	<!-- Simple type definitions used to constrain values of attributes -->
-	<xsd:simpleType name="domainNameType">
-		<xsd:restriction base="xsd:string">
-			<xsd:pattern
-				value="([a-zA-Z0-9][a-zA-Z0-9'\-']*[a-zA-Z0-9]\.)*([a-zA-Z0-9][a-zA-Z0-9'\-']*[a-zA-Z0-9])?" />
-			<xsd:maxLength value="255" />
-		</xsd:restriction>
-	</xsd:simpleType>
-</xsd:schema> 
-  
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/src/main/xsd/xmlds.xsd
----------------------------------------------------------------------
diff --git a/server-usagerecord/src/main/xsd/xmlds.xsd b/server-usagerecord/src/main/xsd/xmlds.xsd
deleted file mode 100644
index c3421c4..0000000
--- a/server-usagerecord/src/main/xsd/xmlds.xsd
+++ /dev/null
@@ -1,318 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE schema
-  PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"
- [
-   <!ATTLIST schema 
-     xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
-   <!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
-   <!ENTITY % p ''>
-   <!ENTITY % s ''>
-  ]>
-
-<!-- Schema for XML Signatures
-    http://www.w3.org/2000/09/xmldsig#
-    $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
-
-    Copyright 2001 The Internet Society and W3C (Massachusetts Institute
-    of Technology, Institut National de Recherche en Informatique et en
-    Automatique, Keio University). All Rights Reserved.
-    http://www.w3.org/Consortium/Legal/
-
-    This document is governed by the W3C Software License [1] as described
-    in the FAQ [2].
-
-    [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
-    [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
--->
-
-
-<schema xmlns="http://www.w3.org/2001/XMLSchema"
-        xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
-        targetNamespace="http://www.w3.org/2000/09/xmldsig#"
-        version="0.1" elementFormDefault="qualified"> 
-
-<!-- Basic Types Defined for Signatures -->
-
-<simpleType name="CryptoBinary">
-  <restriction base="base64Binary">
-  </restriction>
-</simpleType>
-
-<!-- Start Signature -->
-
-<element name="Signature" type="ds:SignatureType"/>
-<complexType name="SignatureType">
-  <sequence> 
-    <element ref="ds:SignedInfo"/> 
-    <element ref="ds:SignatureValue"/> 
-    <element ref="ds:KeyInfo" minOccurs="0"/> 
-    <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 
-  </sequence>  
-  <attribute name="Id" type="ID" use="optional"/>
-</complexType>
-
-  <element name="SignatureValue" type="ds:SignatureValueType"/> 
-  <complexType name="SignatureValueType">
-    <simpleContent>
-      <extension base="base64Binary">
-        <attribute name="Id" type="ID" use="optional"/>
-      </extension>
-    </simpleContent>
-  </complexType>
-
-<!-- Start SignedInfo -->
-
-<element name="SignedInfo" type="ds:SignedInfoType"/>
-<complexType name="SignedInfoType">
-  <sequence> 
-    <element ref="ds:CanonicalizationMethod"/> 
-    <element ref="ds:SignatureMethod"/> 
-    <element ref="ds:Reference" maxOccurs="unbounded"/> 
-  </sequence>  
-  <attribute name="Id" type="ID" use="optional"/> 
-</complexType>
-
-  <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/> 
-  <complexType name="CanonicalizationMethodType" mixed="true">
-    <sequence>
-      <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
-      <!-- (0,unbounded) elements from (1,1) namespace -->
-    </sequence>
-    <attribute name="Algorithm" type="anyURI" use="required"/> 
-  </complexType>
-
-  <element name="SignatureMethod" type="ds:SignatureMethodType"/>
-  <complexType name="SignatureMethodType" mixed="true">
-    <sequence>
-      <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
-      <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
-      <!-- (0,unbounded) elements from (1,1) external namespace -->
-    </sequence>
-    <attribute name="Algorithm" type="anyURI" use="required"/> 
-  </complexType>
-
-<!-- Start Reference -->
-
-<element name="Reference" type="ds:ReferenceType"/>
-<complexType name="ReferenceType">
-  <sequence> 
-    <element ref="ds:Transforms" minOccurs="0"/> 
-    <element ref="ds:DigestMethod"/> 
-    <element ref="ds:DigestValue"/> 
-  </sequence>
-  <attribute name="Id" type="ID" use="optional"/> 
-  <attribute name="URI" type="anyURI" use="optional"/> 
-  <attribute name="Type" type="anyURI" use="optional"/> 
-</complexType>
-
-  <element name="Transforms" type="ds:TransformsType"/>
-  <complexType name="TransformsType">
-    <sequence>
-      <element ref="ds:Transform" maxOccurs="unbounded"/>  
-    </sequence>
-  </complexType>
-
-  <element name="Transform" type="ds:TransformType"/>
-  <complexType name="TransformType" mixed="true">
-    <choice minOccurs="0" maxOccurs="unbounded"> 
-      <any namespace="##other" processContents="lax"/>
-      <!-- (1,1) elements from (0,unbounded) namespaces -->
-      <element name="XPath" type="string"/> 
-    </choice>
-    <attribute name="Algorithm" type="anyURI" use="required"/> 
-  </complexType>
-
-<!-- End Reference -->
-
-<element name="DigestMethod" type="ds:DigestMethodType"/>
-<complexType name="DigestMethodType" mixed="true"> 
-  <sequence>
-    <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
-  </sequence>    
-  <attribute name="Algorithm" type="anyURI" use="required"/> 
-</complexType>
-
-<element name="DigestValue" type="ds:DigestValueType"/>
-<simpleType name="DigestValueType">
-  <restriction base="base64Binary"/>
-</simpleType>
-
-<!-- End SignedInfo -->
-
-<!-- Start KeyInfo -->
-
-<element name="KeyInfo" type="ds:KeyInfoType"/> 
-<complexType name="KeyInfoType" mixed="true">
-  <choice maxOccurs="unbounded">     
-    <element ref="ds:KeyName"/> 
-    <element ref="ds:KeyValue"/> 
-    <element ref="ds:RetrievalMethod"/> 
-    <element ref="ds:X509Data"/> 
-    <element ref="ds:PGPData"/> 
-    <element ref="ds:SPKIData"/>
-    <element ref="ds:MgmtData"/>
-    <any processContents="lax" namespace="##other"/>
-    <!-- (1,1) elements from (0,unbounded) namespaces -->
-  </choice>
-  <attribute name="Id" type="ID" use="optional"/> 
-</complexType>
-
-  <element name="KeyName" type="string"/>
-  <element name="MgmtData" type="string"/>
-
-  <element name="KeyValue" type="ds:KeyValueType"/> 
-  <complexType name="KeyValueType" mixed="true">
-   <choice>
-     <element ref="ds:DSAKeyValue"/>
-     <element ref="ds:RSAKeyValue"/>
-     <any namespace="##other" processContents="lax"/>
-   </choice>
-  </complexType>
-
-  <element name="RetrievalMethod" type="ds:RetrievalMethodType"/> 
-  <complexType name="RetrievalMethodType">
-    <sequence>
-      <element ref="ds:Transforms" minOccurs="0"/> 
-    </sequence>  
-    <attribute name="URI" type="anyURI"/>
-    <attribute name="Type" type="anyURI" use="optional"/>
-  </complexType>
-
-<!-- Start X509Data -->
-
-<element name="X509Data" type="ds:X509DataType"/> 
-<complexType name="X509DataType">
-  <sequence maxOccurs="unbounded">
-    <choice>
-      <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
-      <element name="X509SKI" type="base64Binary"/>
-      <element name="X509SubjectName" type="string"/>
-      <element name="X509Certificate" type="base64Binary"/>
-      <element name="X509CRL" type="base64Binary"/>
-      <any namespace="##other" processContents="lax"/>
-    </choice>
-  </sequence>
-</complexType>
-
-<complexType name="X509IssuerSerialType"> 
-  <sequence> 
-    <element name="X509IssuerName" type="string"/> 
-    <element name="X509SerialNumber" type="integer"/> 
-  </sequence>
-</complexType>
-
-<!-- End X509Data -->
-
-<!-- Begin PGPData -->
-
-<element name="PGPData" type="ds:PGPDataType"/> 
-<complexType name="PGPDataType"> 
-  <choice>
-    <sequence>
-      <element name="PGPKeyID" type="base64Binary"/> 
-      <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/> 
-      <any namespace="##other" processContents="lax" minOccurs="0"
-       maxOccurs="unbounded"/>
-    </sequence>
-    <sequence>
-      <element name="PGPKeyPacket" type="base64Binary"/> 
-      <any namespace="##other" processContents="lax" minOccurs="0"
-       maxOccurs="unbounded"/>
-    </sequence>
-  </choice>
-</complexType>
-
-<!-- End PGPData -->
-
-<!-- Begin SPKIData -->
-
-<element name="SPKIData" type="ds:SPKIDataType"/> 
-<complexType name="SPKIDataType">
-  <sequence maxOccurs="unbounded">
-    <element name="SPKISexp" type="base64Binary"/>
-    <any namespace="##other" processContents="lax" minOccurs="0"/>
-  </sequence>
-</complexType> 
-
-<!-- End SPKIData -->
-
-<!-- End KeyInfo -->
-
-<!-- Start Object (Manifest, SignatureProperty) -->
-
-<element name="Object" type="ds:ObjectType"/> 
-<complexType name="ObjectType" mixed="true">
-  <sequence minOccurs="0" maxOccurs="unbounded">
-    <any namespace="##any" processContents="lax"/>
-  </sequence>
-  <attribute name="Id" type="ID" use="optional"/> 
-  <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
-  <attribute name="Encoding" type="anyURI" use="optional"/> 
-</complexType>
-
-<element name="Manifest" type="ds:ManifestType"/> 
-<complexType name="ManifestType">
-  <sequence>
-    <element ref="ds:Reference" maxOccurs="unbounded"/> 
-  </sequence>
-  <attribute name="Id" type="ID" use="optional"/> 
-</complexType>
-
-<element name="SignatureProperties" type="ds:SignaturePropertiesType"/> 
-<complexType name="SignaturePropertiesType">
-  <sequence>
-    <element ref="ds:SignatureProperty" maxOccurs="unbounded"/> 
-  </sequence>
-  <attribute name="Id" type="ID" use="optional"/> 
-</complexType>
-
-   <element name="SignatureProperty" type="ds:SignaturePropertyType"/> 
-   <complexType name="SignaturePropertyType" mixed="true">
-     <choice maxOccurs="unbounded">
-       <any namespace="##other" processContents="lax"/>
-       <!-- (1,1) elements from (1,unbounded) namespaces -->
-     </choice>
-     <attribute name="Target" type="anyURI" use="required"/> 
-     <attribute name="Id" type="ID" use="optional"/> 
-   </complexType>
-
-<!-- End Object (Manifest, SignatureProperty) -->
-
-<!-- Start Algorithm Parameters -->
-
-<simpleType name="HMACOutputLengthType">
-  <restriction base="integer"/>
-</simpleType>
-
-<!-- Start KeyValue Element-types -->
-
-<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
-<complexType name="DSAKeyValueType">
-  <sequence>
-    <sequence minOccurs="0">
-      <element name="P" type="ds:CryptoBinary"/>
-      <element name="Q" type="ds:CryptoBinary"/>
-    </sequence>
-    <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
-    <element name="Y" type="ds:CryptoBinary"/>
-    <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
-    <sequence minOccurs="0">
-      <element name="Seed" type="ds:CryptoBinary"/>
-      <element name="PgenCounter" type="ds:CryptoBinary"/>
-    </sequence>
-  </sequence>
-</complexType>
-
-<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
-<complexType name="RSAKeyValueType">
-  <sequence>
-    <element name="Modulus" type="ds:CryptoBinary"/> 
-    <element name="Exponent" type="ds:CryptoBinary"/> 
-  </sequence>
-</complexType> 
-
-<!-- End KeyValue Element-types -->
-
-<!-- End Signature -->
-
-</schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-usagerecord/src/test/java/TestUR.java
----------------------------------------------------------------------
diff --git a/server-usagerecord/src/test/java/TestUR.java b/server-usagerecord/src/test/java/TestUR.java
deleted file mode 100644
index 42e9000..0000000
--- a/server-usagerecord/src/test/java/TestUR.java
+++ /dev/null
@@ -1,120 +0,0 @@
-import static java.lang.Runtime.getRuntime;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.JAXBIntrospector;
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.datatype.DatatypeConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.ogf.usage.JobUsageRecord;
-import org.ogf.usage.v1_0.Charge;
-import org.ogf.usage.v1_0.CpuDuration;
-import org.ogf.usage.v1_0.Disk;
-import org.ogf.usage.v1_0.EndTime;
-import org.ogf.usage.v1_0.Host;
-import org.ogf.usage.v1_0.JobIdentity;
-import org.ogf.usage.v1_0.JobName;
-import org.ogf.usage.v1_0.MachineName;
-import org.ogf.usage.v1_0.Memory;
-import org.ogf.usage.v1_0.Network;
-import org.ogf.usage.v1_0.NodeCount;
-import org.ogf.usage.v1_0.PhaseResource;
-import org.ogf.usage.v1_0.Processors;
-import org.ogf.usage.v1_0.ProjectName;
-import org.ogf.usage.v1_0.Queue;
-import org.ogf.usage.v1_0.RecordIdentity;
-import org.ogf.usage.v1_0.ServiceLevel;
-import org.ogf.usage.v1_0.StartTime;
-import org.ogf.usage.v1_0.Status;
-import org.ogf.usage.v1_0.SubmitHost;
-import org.ogf.usage.v1_0.Swap;
-import org.ogf.usage.v1_0.TimeDuration;
-import org.ogf.usage.v1_0.TimeInstant;
-import org.ogf.usage.v1_0.UserIdentity;
-import org.ogf.usage.v1_0.VolumeResource;
-import org.ogf.usage.v1_0.WallDuration;
-
-public class TestUR {
-	SchemaOutputResolver sink;
-	StringWriter writer;
-
-	String result() {
-		return writer.toString();
-	}
-
-	@Before
-	public void setUp() throws Exception {
-		writer = new StringWriter();
-		sink = new SchemaOutputResolver() {
-			@Override
-			public Result createOutput(String namespaceUri,
-					String suggestedFileName) throws IOException {
-				StreamResult sr = new StreamResult(writer);
-				sr.setSystemId("/dev/null");
-				return sr;
-			}
-		};
-		Assert.assertNull(null);// Shut up, Eclipse!
-		Assert.assertEquals("", result());
-	}
-
-	@Test
-	public void testSchema() throws JAXBException, IOException {
-		JAXBContext.newInstance(JobUsageRecord.class).generateSchema(sink);
-		Assert.assertNotSame("", result());
-	}
-
-	@Test
-	public void testSchemaCompleteness() throws JAXBException, DatatypeConfigurationException {
-		JAXBIntrospector info = JAXBContext.newInstance(JobUsageRecord.class).createJAXBIntrospector();
-		Assert.assertTrue(info.isElement(new Charge()));
-		Assert.assertTrue(info.isElement(new CpuDuration()));
-		Assert.assertTrue(info.isElement(new Disk()));
-		Assert.assertTrue(info.isElement(new EndTime()));
-		Assert.assertTrue(info.isElement(new Host()));
-		Assert.assertTrue(info.isElement(new JobIdentity()));
-		Assert.assertTrue(info.isElement(new JobName()));
-		Assert.assertTrue(info.isElement(new JobUsageRecord()));
-		Assert.assertTrue(info.isElement(new MachineName()));
-		Assert.assertTrue(info.isElement(new Memory()));
-		Assert.assertTrue(info.isElement(new Network()));
-		Assert.assertTrue(info.isElement(new NodeCount()));
-		Assert.assertTrue(info.isElement(new PhaseResource()));
-		Assert.assertTrue(info.isElement(new Processors()));
-		Assert.assertTrue(info.isElement(new ProjectName()));
-		Assert.assertTrue(info.isElement(new Queue()));
-		Assert.assertTrue(info.isElement(new RecordIdentity()));
-		Assert.assertTrue(info.isElement(new ServiceLevel()));
-		Assert.assertTrue(info.isElement(new StartTime()));
-		Assert.assertTrue(info.isElement(new Status()));
-		Assert.assertTrue(info.isElement(new SubmitHost()));
-		Assert.assertTrue(info.isElement(new Swap()));
-		Assert.assertTrue(info.isElement(new TimeDuration()));
-		Assert.assertTrue(info.isElement(new TimeInstant()));
-		Assert.assertTrue(info.isElement(new UserIdentity()));
-		Assert.assertTrue(info.isElement(new VolumeResource()));
-		Assert.assertTrue(info.isElement(new WallDuration()));
-	}
-
-	@Test
-	public void testGenerate() throws DatatypeConfigurationException,
-			JAXBException {
-		JobUsageRecord ur = new JobUsageRecord();
-		ur.setStatus("Completed");
-		ur.addWallDuration(1000 * 65);
-		ur.addHost("localhost");
-		ur.addMemory(getRuntime().totalMemory() - getRuntime().freeMemory()).setType("vm");
-
-		String record = ur.marshal();
-		Assert.assertNotSame("", record);
-		//System.out.println(record);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/.gitignore
----------------------------------------------------------------------
diff --git a/server-webapp/.gitignore b/server-webapp/.gitignore
deleted file mode 100644
index ea8c4bf..0000000
--- a/server-webapp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/.springBeans
----------------------------------------------------------------------
diff --git a/server-webapp/.springBeans b/server-webapp/.springBeans
deleted file mode 100644
index 0b2cbbc..0000000
--- a/server-webapp/.springBeans
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beansProjectDescription>
-	<version>1</version>
-	<pluginVersion><![CDATA[3.3.0.201307091516-RELEASE]]></pluginVersion>
-	<configSuffixes>
-		<configSuffix><![CDATA[xml]]></configSuffix>
-	</configSuffixes>
-	<enableImports><![CDATA[true]]></enableImports>
-	<configs>
-		<config>src/main/webapp/WEB-INF/beans.xml</config>
-		<config>src/test/resources/example.xml</config>
-		<config>src/main/webapp/WEB-INF/insecure.xml</config>
-		<config>src/main/webapp/WEB-INF/providers.xml</config>
-		<config>src/main/webapp/WEB-INF/secure.xml</config>
-		<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-		<config>src/main/webapp/WEB-INF/partsecure.xml</config>
-	</configs>
-	<configSets>
-		<configSet>
-			<name><![CDATA[Secure Configuration]]></name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/secure.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-		<configSet>
-			<name><![CDATA[Insecure Configuration]]></name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/insecure.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-		<configSet>
-			<name><![CDATA[Semi-Secure Configuration]]></name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-				<config>src/main/webapp/WEB-INF/partsecure.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-	</configSets>
-</beansProjectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/pom.xml
----------------------------------------------------------------------
diff --git a/server-webapp/pom.xml b/server-webapp/pom.xml
deleted file mode 100644
index f4cf0ef..0000000
--- a/server-webapp/pom.xml
+++ /dev/null
@@ -1,889 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>org.apache.taverna.server</groupId>
-		<artifactId>taverna-server</artifactId>
-		<version>3.1.0-incubating-SNAPSHOT</version>
-	</parent>
-	<artifactId>taverna-server-webapp</artifactId>
-	<packaging>war</packaging>
-	<name>Apache Taverna Server Web Application Core</name>
-	<description>This is the implementation of the web-app that provides the Taverna Server with its SOAP and REST faces. It relies on the worker process to handle the actual launching of workflow runs.</description>
-
-	<properties>
-		<version.cxf>2.7.7</version.cxf>
-		<version.spring>3.2.5.RELEASE</version.spring>
-		<version.spring-security>3.1.4.RELEASE</version.spring-security>
-		<version.asm>3.3.1</version.asm>
-		<version.smack>3.2.1</version.smack>
-		<version.jdoapi>3.0.1</version.jdoapi>
-		<forker.module>taverna-server-unix-forker</forker.module>
-		<util.dir>${project.build.directory}/${project.build.finalName}/WEB-INF/classes/util</util.dir>
-		<cmdline.dir>${util.dir}/taverna-commandline-${edition.commandline}-${version.commandline}</cmdline.dir>
-	</properties>
-
-	<dependencies>
-		<dependency>
-			<groupId>org.apache.cxf</groupId>
-			<artifactId>cxf-rt-frontend-jaxws</artifactId>
-			<version>${version.cxf}</version>
-			<exclusions>
-				<exclusion>
-					<artifactId>jaxb-impl</artifactId>
-					<groupId>com.sun.xml.bind</groupId>
-				</exclusion>
-			</exclusions>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.cxf</groupId>
-			<artifactId>cxf-rt-frontend-jaxrs</artifactId>
-			<version>${version.cxf}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.cxf</groupId>
-			<artifactId>cxf-rt-transports-http</artifactId>
-			<version>${version.cxf}</version>
-		</dependency>
-		<dependency>
-			<groupId>commons-logging</groupId>
-			<artifactId>commons-logging</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>commons-io</groupId>
-			<artifactId>commons-io</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-aop</artifactId>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework.security</groupId>
-			<artifactId>spring-security-core</artifactId>
-			<version>${version.spring-security}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework.security</groupId>
-			<artifactId>spring-security-web</artifactId>
-			<version>${version.spring-security}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework.security</groupId>
-			<artifactId>spring-security-config</artifactId>
-			<version>${version.spring-security}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-test</artifactId>
-			<version>${version.spring}</version>
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>junit</groupId>
-			<artifactId>junit</artifactId><!--$NO-MVN-MAN-VER$-->
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-port-description</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-runinterface</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-usagerecord</artifactId>
-			<version>${project.parent.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-worker</artifactId>
-			<version>${project.parent.version}</version>
-			<classifier>jar-with-dependencies</classifier>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>${forker.module}</artifactId>
-			<version>${project.parent.version}</version>
-			<classifier>jar-with-dependencies</classifier>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>${project.parent.groupId}</groupId>
-			<artifactId>taverna-server-rmidaemon</artifactId>
-			<version>${project.parent.version}</version>
-			<classifier>jar-with-dependencies</classifier>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>servlet-api</artifactId>
-			<version>2.5</version>
-			<scope>provided</scope>
-		</dependency>
-		<!--
-		<dependency>
-			<groupId>org.hibernate</groupId>
-			<artifactId>hibernate-annotations</artifactId>
-			<version>3.4.0.GA</version>
-			<scope>compile</scope>
-		</dependency>
-		-->
-		<!--
-		<dependency>
-			<groupId>org.hibernate</groupId>
-			<artifactId>hibernate-validator</artifactId>
-			<version>4.0.2.GA</version>
-			<scope>compile</scope>
-		</dependency>
-		-->
-		<dependency>
-			<groupId>org.apache.derby</groupId>
-			<artifactId>derby</artifactId>
-			<version>10.10.1.1</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>commons-dbcp</groupId>
-			<artifactId>commons-dbcp</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>javax.jdo</groupId>
-			<artifactId>jdo-api</artifactId>
-			<version>3.0.1</version>
-		</dependency>
-		<dependency>
-			<groupId>org.datanucleus</groupId>
-			<artifactId>datanucleus-api-jdo</artifactId>
-			<version>[3.2.0, 3.2.99)</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.datanucleus</groupId>
-			<artifactId>datanucleus-core</artifactId>
-			<version>3.2.10</version>
-		</dependency>
-		<dependency>
-			<groupId>org.datanucleus</groupId>
-			<artifactId>datanucleus-rdbms</artifactId>
-			<version>[3.2.0, 3.2.99)</version>
-			<scope>compile</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.jdo</groupId>
-			<artifactId>jdo2-core</artifactId>
-			<version>2.0</version>
-		</dependency>
-		<dependency>
-			<groupId>joda-time</groupId>
-			<artifactId>joda-time</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>net.sf.mime-util</groupId>
-			<artifactId>mime-util</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.twitter4j</groupId>
-			<artifactId>twitter4j-core</artifactId>
-			<version>[3.0,)</version>
-		</dependency>
-		<dependency>
-			<groupId>cglib</groupId>
-			<artifactId>cglib</artifactId>
-			<version>3.0</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.aspectj</groupId>
-			<artifactId>aspectjrt</artifactId>
-			<version>1.7.4</version>
-		</dependency>
-		<dependency>
-			<groupId>org.igniterealtime.smack</groupId>
-			<artifactId>smack</artifactId>
-			<version>${version.smack}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.igniterealtime.smack</groupId>
-			<artifactId>smackx</artifactId>
-			<version>${version.smack}</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.httpcomponents</groupId>
-			<artifactId>httpclient</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>javax.annotation</groupId>
-			<artifactId>jsr250-api</artifactId>
-			<version>1.0</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.abdera</groupId>
-			<artifactId>abdera-core</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.abdera</groupId>
-			<artifactId>abdera-parser</artifactId>
-			<version>1.1.3</version>
-			<scope>runtime</scope>
-			<exclusions>
-				<exclusion>
-					<artifactId>xercesImpl</artifactId>
-					<groupId>xerces</groupId>
-				</exclusion>
-			</exclusions>
-		</dependency>
-		<dependency>
-			<groupId>org.bouncycastle</groupId>
-			<artifactId>bcprov-jdk15on</artifactId>
-			<version>1.49</version>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-context-support</artifactId>
-			<version>${version.spring}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.aspectj</groupId>
-			<artifactId>aspectjweaver</artifactId>
-			<version>1.7.4</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>javax.mail</groupId>
-			<artifactId>mail</artifactId>
-			<version>1.4.4</version>
-			<scope>runtime</scope>
-			<exclusions>
-				<exclusion>
-					<groupId>javax.activation</groupId>
-					<artifactId>activation</artifactId>
-				</exclusion>
-			</exclusions>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.velocity</groupId>
-			<artifactId>velocity</artifactId>
-			<version>1.7</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.cxf</groupId>
-			<artifactId>cxf-rt-rs-extension-providers</artifactId>
-			<version>${version.cxf}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.codehaus.jettison</groupId>
-			<artifactId>jettison</artifactId>
-			<version>1.3.4</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-api</artifactId>
-			<version>${taverna.language.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-t2flow</artifactId>
-			<version>${taverna.language.version}</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.taverna.language</groupId>
-			<artifactId>taverna-scufl2-wfbundle</artifactId>
-			<version>${taverna.language.version}</version>
-			<scope>runtime</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.commons</groupId>
-			<artifactId>commons-compress</artifactId>
-			<version>1.4.1</version>
-		</dependency>
-	</dependencies>
-
-	<dependencyManagement>
-		<dependencies>
-			<dependency>
-				<groupId>${project.parent.groupId}</groupId>
-				<artifactId>taverna-server-runinterface</artifactId>
-				<version>${project.parent.version}</version>
-				<scope>compile</scope>
-			</dependency>
-			<dependency>
-				<groupId>asm</groupId>
-				<artifactId>asm</artifactId>
-				<version>${version.asm}</version>
-				<scope>runtime</scope>
-			</dependency>
-			<dependency>
-				<groupId>com.sun.xml.bind</groupId>
-				<artifactId>jaxb-impl</artifactId>
-				<version>2.2.7</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-aop</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-core</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-beans</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-web</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-jdbc</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-tx</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-context</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.springframework</groupId>
-				<artifactId>spring-expression</artifactId>
-				<version>${version.spring}</version>
-			</dependency>
-			<dependency>
-				<groupId>org.apache.abdera</groupId>
-				<artifactId>abdera-core</artifactId>
-				<version>1.1.3</version>
-			</dependency>
-			<dependency>
-				<groupId>org.codehaus.woodstox</groupId>
-				<artifactId>wstx-asl</artifactId>
-				<version>4.0.6</version>
-			</dependency>
-			<dependency>
-				<groupId>org.apache.geronimo.specs</groupId>
-				<artifactId>geronimo-javamail_1.4_spec</artifactId>
-				<version>1.7.1</version>
-				<scope>provided</scope>
-			</dependency>
-			<dependency>
-				<groupId>org.codehaus.woodstox</groupId>
-				<artifactId>woodstox-core-asl</artifactId>
-				<version>4.2.0</version>
-				<scope>runtime</scope>
-			</dependency>
-			<dependency>
-				<groupId>jaxen</groupId>
-				<artifactId>jaxen</artifactId>
-				<version>1.1.4</version>
-			</dependency>
-		</dependencies>
-	</dependencyManagement>
-
-	<build>
-		<finalName>TavernaServer.${project.parent.version}</finalName>
-		<pluginManagement>
-			<plugins>
-				<plugin>
-					<groupId>org.codehaus.mojo</groupId>
-					<artifactId>tomcat-maven-plugin</artifactId>
-					<version>1.1</version>
-					<configuration>
-						<server>deployhost</server>
-						<path>/taverna-server</path>
-					</configuration>
-				</plugin>
-				<plugin>
-					<groupId>org.apache.maven.plugins</groupId>
-					<artifactId>maven-compiler-plugin</artifactId>
-					<configuration>
-						<encoding>US-ASCII</encoding>
-						<source>1.7</source>
-						<target>1.7</target>
-					</configuration>
-				</plugin>
-				<plugin>
-					<groupId>org.datanucleus</groupId>
-					<artifactId>datanucleus-maven-plugin</artifactId>
-					<version>3.3.0-release</version>
-					<configuration>
-						<jdkLogConfiguration>${project.basedir}/src/build/resources/datanucleus-log.properties</jdkLogConfiguration>
-						<log4jConfiguration>${project.basedir}/src/build/resources/datanucleus_log4j.properties</log4jConfiguration>
-						<verbose>true</verbose>
-					</configuration>
-					<dependencies>
-						<!-- Sucks that I have to say these explicitly -->
-						<dependency>
-							<groupId>org.datanucleus</groupId>
-							<artifactId>datanucleus-core</artifactId>
-							<version>3.2.10</version>
-						</dependency>
-						<dependency>
-							<groupId>org.datanucleus</groupId>
-							<artifactId>datanucleus-enhancer</artifactId>
-							<version>3.1.1</version>
-						</dependency>
-						<dependency>
-							<groupId>org.datanucleus</groupId>
-							<artifactId>datanucleus-api-jdo</artifactId>
-							<version>3.2.5</version>
-						</dependency>
-						<dependency>
-							<groupId>javax.jdo</groupId>
-							<artifactId>jdo-api</artifactId>
-							<version>${version.jdoapi}</version>
-						</dependency>
-					</dependencies>
-				</plugin>
-				<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
-				<plugin>
-					<groupId>org.eclipse.m2e</groupId>
-					<artifactId>lifecycle-mapping</artifactId>
-					<version>1.0.0</version>
-					<configuration>
-						<lifecycleMappingMetadata>
-							<pluginExecutions>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>org.apache.maven.plugins</groupId>
-										<artifactId>maven-dependency-plugin</artifactId>
-										<versionRange>[2.0,)</versionRange>
-										<goals>
-											<goal>copy-dependencies</goal>
-											<goal>unpack</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<ignore />
-									</action>
-								</pluginExecution>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>org.datanucleus</groupId>
-										<artifactId>datanucleus-maven-plugin</artifactId>
-										<versionRange>3.3.0-release</versionRange>
-										<goals>
-											<goal>enhance</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute />
-									</action>
-								</pluginExecution>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>pl.project13.maven</groupId>
-										<artifactId>git-commit-id-plugin</artifactId>
-										<versionRange>[2.1.4,)</versionRange>
-										<goals>
-											<goal>revision</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute />
-									</action>
-								</pluginExecution>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>org.datanucleus</groupId>
-										<artifactId>datanucleus-maven-plugin</artifactId>
-										<versionRange>3.3.0-release</versionRange>
-										<goals>
-											<goal>schema-create</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<ignore />
-									</action>
-								</pluginExecution>
-								<pluginExecution>
-									<pluginExecutionFilter>
-										<groupId>net.alchim31.maven</groupId>
-										<artifactId>yuicompressor-maven-plugin</artifactId>
-										<versionRange>[1.0.0,)</versionRange>
-										<goals>
-											<goal>compress</goal>
-										</goals>
-									</pluginExecutionFilter>
-									<action>
-										<execute/>
-									</action>
-								</pluginExecution>
-							</pluginExecutions>
-						</lifecycleMappingMetadata>
-					</configuration>
-				</plugin>
-			</plugins>
-		</pluginManagement>
-
-		<defaultGoal>package</defaultGoal>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-dependency-plugin</artifactId>
-				<executions>
-					<execution>
-						<id>copy-executable-library-jars</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>copy</goal>
-						</goals>
-						<configuration>
-							<artifactItems>
-								<artifactItem>
-									<groupId>${project.parent.groupId}</groupId>
-									<artifactId>taverna-server-worker</artifactId>
-									<version>${project.parent.version}</version>
-									<classifier>jar-with-dependencies</classifier>
-									<overWrite>false</overWrite>
-									<destFileName>server.worker.jar</destFileName>
-								</artifactItem>
-								<artifactItem>
-									<groupId>${project.parent.groupId}</groupId>
-									<artifactId>${forker.module}</artifactId>
-									<version>${project.parent.version}</version>
-									<classifier>jar-with-dependencies</classifier>
-									<overWrite>false</overWrite>
-									<destFileName>secure.fork.jar</destFileName>
-								</artifactItem>
-								<artifactItem>
-									<groupId>${project.parent.groupId}</groupId>
-									<artifactId>taverna-server-rmidaemon</artifactId>
-									<version>${project.parent.version}</version>
-									<classifier>jar-with-dependencies</classifier>
-									<overWrite>false</overWrite>
-									<destFileName>rmi.daemon.jar</destFileName>
-								</artifactItem>
-							</artifactItems>
-							<outputDirectory>${util.dir}</outputDirectory>
-							<overWriteReleases>false</overWriteReleases>
-							<overWriteSnapshots>true</overWriteSnapshots>
-							<excludeTransitive>true</excludeTransitive>
-						</configuration>
-					</execution>
-					<execution>
-						<id>unpack-taverna-commandline</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>unpack</goal>
-						</goals>
-						<configuration>
-							<artifactItems>
-								<artifactItem>
-									<groupId>org.apache.taverna.commandline</groupId>
-									<artifactId>taverna-commandline</artifactId>
-									<version>${taverna.commandline.version}</version>
-									<classifier>bin</classifier>
-									<type>zip</type>
-									<classifier>bin</classifier>
-									<outputDirectory>${util.dir}</outputDirectory>
-								</artifactItem>
-							</artifactItems>
-							<overWriteReleases>false</overWriteReleases>
-							<overWriteSnapshots>true</overWriteSnapshots>
-							<excludeTransitive>true</excludeTransitive>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
-			<plugin>
-				<groupId>org.datanucleus</groupId>
-				<artifactId>datanucleus-maven-plugin</artifactId>
-				<configuration>
-					<fork>false</fork>
-					<metadataIncludes>
-						org/taverna/server/master/*.class,
-						org/taverna/server/master/identity/*.class,
-						org/taverna/server/master/localworker/*.class,
-						org/taverna/server/master/notification/atom/*.class,
-						org/taverna/server/master/usage/*.class,
-						org/taverna/server/master/worker/*.class
-					</metadataIncludes>
-				</configuration>
-				<executions>
-					<execution>
-						<id>enhance</id>
-						<phase>process-classes</phase>
-						<goals>
-							<goal>enhance</goal>
-						</goals>
-					</execution>
-					<!--
-					<execution>
-						<id>gen-db-schema</id>
-						<phase>process-classes</phase>
-						<goals>
-							<goal>schema-create</goal>
-						</goals>
-						<configuration>
-							<completeDdl>true</completeDdl>
-							<ddlFile>${util.dir}/schema.sql</ddlFile>
-						</configuration>
-					</execution>
-					-->
-				</executions>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-compiler-plugin</artifactId>
-				<configuration>
-					<encoding>US-ASCII</encoding>
-					<source>1.7</source>
-					<target>1.7</target>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>pl.project13.maven</groupId>
-				<artifactId>git-commit-id-plugin</artifactId>
-				<version>2.1.4</version>
-				<executions>
-					<execution>
-						<id>buildinfo</id>
-						<phase>generate-resources</phase>
-						<goals>
-							<goal>revision</goal>
-						</goals>
-					</execution>
-				</executions>
-				<configuration>
-					<dotGitDirectory>${project.basedir}/../.git</dotGitDirectory>
-					<prefix>git</prefix>
-					<verbose>true</verbose>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-war-plugin</artifactId>
-				<version>2.4</version>
-				<configuration>
-					<webXml>src/main/webapp/WEB-INF/web-sec.xml</webXml>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-eclipse-plugin</artifactId>
-				<configuration>
-					<additionalProjectnatures>
-						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
-					</additionalProjectnatures>
-					<additionalConfig>
-						<file>
-							<name>.springBeans</name>
-							<content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
-<beansProjectDescription>
-	<version>1</version>
-	<pluginVersion>3.3.0.201307091516-RELEASE</pluginVersion>
-	<configSuffixes>
-		<configSuffix>xml</configSuffix>
-	</configSuffixes>
-	<enableImports>true</enableImports>
-	<configs>
-		<config>src/main/webapp/WEB-INF/partsecure.xml</config>
-		<config>src/main/webapp/WEB-INF/beans.xml</config>
-		<config>src/main/webapp/WEB-INF/insecure.xml</config>
-		<config>src/main/webapp/WEB-INF/providers.xml</config>
-		<config>src/main/webapp/WEB-INF/secure.xml</config>
-		<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-	</configs>
-	<configSets>
-		<configSet>
-			<name>Secure Configuration</name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/secure.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-		<configSet>
-			<name>Insecure Configuration</name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/insecure.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-		<configSet>
-			<name>Semi-Secure Configuration</name>
-			<allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
-			<incomplete>false</incomplete>
-			<configs>
-				<config>src/main/webapp/WEB-INF/beans.xml</config>
-				<config>src/main/webapp/WEB-INF/providers.xml</config>
-				<config>src/main/webapp/WEB-INF/webappBeans.xml</config>
-				<config>src/main/webapp/WEB-INF/partsecure.xml</config>
-			</configs>
-			<profiles>
-			</profiles>
-		</configSet>
-	</configSets>
-</beansProjectDescription>]]></content>
-						</file>
-					</additionalConfig>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>net.alchim31.maven</groupId>
-				<artifactId>yuicompressor-maven-plugin</artifactId>
-				<version>1.4.0</version>
-				<executions>
-					<execution>
-						<goals>
-							<goal>compress</goal>
-						</goals>
-					</execution>
-				</executions>
-				<configuration>
-					<excludes>
-						<exclude>**/*.min.js</exclude>
-					</excludes>
-					<nosuffix>true</nosuffix>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-resources-plugin</artifactId>
-				<executions>
-					<execution>
-						<id>override-executeworkflow-scripts</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>copy-resources</goal>
-						</goals>
-						<configuration>
-							<outputDirectory>${cmdline.dir}</outputDirectory>
-							<resources>
-								<resource>
-									<directory>src/main/replacementscripts</directory>
-									<filtering>false</filtering>
-								</resource>
-							</resources>
-							<overwrite>true</overwrite>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
-			<plugin>
-				<groupId>org.codehaus.mojo</groupId>
-				<artifactId>exec-maven-plugin</artifactId>
-				<version>1.2.1</version>
-				<executions>
-					<execution>
-						<id>improve-registry-coverage</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>exec</goal>
-						</goals>
-						<configuration>
-							<executable>/bin/sh</executable>
-							<workingDirectory>${cmdline.dir}</workingDirectory>
-							<environmentVariables>
-								<RAVEN_APPHOME>${cmdline.dir}</RAVEN_APPHOME>
-							</environmentVariables>
-							<arguments>
-								<argument>./executeworkflow.sh</argument>
-								<argument>-help</argument>
-							</arguments>
-							<outputFile>/dev/null</outputFile>
-						</configuration>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-		<resources>
-			<resource>
-				<directory>src/main/resources</directory>
-				<filtering>true</filtering>
-			</resource>
-			<resource>
-				<directory>src/main/webapp</directory>
-				<filtering>false</filtering>
-			</resource>
-		</resources>
-	</build>
-
-	<profiles>
-		<profile>
-			<id>unix</id>
-			<properties>
-				<forker.module>taverna-server-unix-forker</forker.module>
-			</properties>
-		</profile>
-		<profile>
-			<id>win</id>
-			<properties>
-				<!-- This doesn't exist yet. -->
-				<forker.module>taverna-server-win-forker</forker.module>
-			</properties>
-		</profile>
-		<profile>
-			<id>nosec</id>
-			<build>
-				<plugins>
-					<plugin>
-						<groupId>org.apache.maven.plugins</groupId>
-						<artifactId>maven-war-plugin</artifactId>
-						<configuration>
-							<webXml>src/main/webapp/WEB-INF/web-nosec.xml</webXml>
-						</configuration>
-					</plugin>
-				</plugins>
-			</build>
-		</profile>
-		<profile>
-			<id>partsec</id>
-			<build>
-				<plugins>
-					<plugin>
-						<groupId>org.apache.maven.plugins</groupId>
-						<artifactId>maven-war-plugin</artifactId>
-						<configuration>
-							<webXml>src/main/webapp/WEB-INF/web-partsec.xml</webXml>
-						</configuration>
-					</plugin>
-				</plugins>
-			</build>
-		</profile>
-	</profiles>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/build/resources/datanucleus_log4j.properties
----------------------------------------------------------------------
diff --git a/server-webapp/src/build/resources/datanucleus_log4j.properties b/server-webapp/src/build/resources/datanucleus_log4j.properties
deleted file mode 100644
index 6707f55..0000000
--- a/server-webapp/src/build/resources/datanucleus_log4j.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-log4j.rootLogger=info, R 
-log4j.appender.R=org.apache.log4j.ConsoleAppender
-log4j.appender.R.layout=org.apache.log4j.PatternLayout
-log4j.appender.R.layout.ConversionPattern=%d{yyyyMMdd'T'HHmmss.SSS} %-5p %c{1} %C{1} - %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java b/server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
deleted file mode 100644
index f5259bd..0000000
--- a/server-webapp/src/main/java/org/taverna/server/master/ContentsDescriptorBuilder.java
+++ /dev/null
@@ -1,292 +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.getMimeType;
-import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM_TYPE;
-import static javax.ws.rs.core.UriBuilder.fromUri;
-import static org.apache.commons.logging.LogFactory.getLog;
-import static org.taverna.server.master.common.Uri.secure;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-
-import org.apache.commons.logging.Log;
-import org.springframework.beans.factory.annotation.Required;
-import org.taverna.server.master.exceptions.FilesystemAccessException;
-import org.taverna.server.master.exceptions.NoDirectoryEntryException;
-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.TavernaRun;
-import org.taverna.server.master.interfaces.UriBuilderFactory;
-import org.taverna.server.master.utils.FilenameUtils;
-import org.taverna.server.port_description.AbsentValue;
-import org.taverna.server.port_description.AbstractPortDescription;
-import org.taverna.server.port_description.AbstractValue;
-import org.taverna.server.port_description.ErrorValue;
-import org.taverna.server.port_description.InputDescription;
-import org.taverna.server.port_description.InputDescription.InputPort;
-import org.taverna.server.port_description.LeafValue;
-import org.taverna.server.port_description.ListValue;
-import org.taverna.server.port_description.OutputDescription;
-import org.taverna.server.port_description.OutputDescription.OutputPort;
-
-import uk.org.taverna.scufl2.api.container.WorkflowBundle;
-import uk.org.taverna.scufl2.api.core.Workflow;
-import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
-import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
-
-/**
- * A class that is used to build descriptions of the contents of a workflow
- * run's filesystem.
- * 
- * @author Donal Fellows
- */
-public class ContentsDescriptorBuilder {
-	private Log log = getLog("Taverna.Server.Webapp");
-	private FilenameUtils fileUtils;
-	private UriBuilderFactory uriBuilderFactory;
-
-	@Required
-	public void setUriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
-		this.uriBuilderFactory = uriBuilderFactory;
-	}
-
-	@Required
-	public void setFileUtils(FilenameUtils fileUtils) {
-		this.fileUtils = fileUtils;
-	}
-
-	// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-	private Workflow fillInFromWorkflow(TavernaRun run, UriBuilder ub,
-			AbstractPortDescription portDesc) throws IOException {
-		WorkflowBundle bundle = run.getWorkflow().getScufl2Workflow();
-		bundle.getMainWorkflow().getInputPorts();
-		portDesc.fillInBaseData(bundle.getMainWorkflow()
-				.getWorkflowIdentifier().toString(), run.getId(), ub.build());
-		return bundle.getMainWorkflow();
-	}
-
-	/**
-	 * Computes the depth of value in a descriptor.
-	 * 
-	 * @param value
-	 *            The value description to characterise.
-	 * @return Its depth (i.e., the depth of the port outputting the value) or
-	 *         <tt>null</tt> if that is impossible to determine.
-	 */
-	private Integer computeDepth(AbstractValue value) {
-		if (value instanceof ListValue) {
-			int mv = 1;
-			for (AbstractValue v : ((ListValue) value).contents) {
-				Integer d = computeDepth(v);
-				if (d != null && mv <= d)
-					mv = d + 1;
-			}
-			return mv;
-		} else if (value instanceof LeafValue || value instanceof ErrorValue)
-			return 0;
-		else
-			return null;
-	}
-
-	/**
-	 * Build a description of a leaf value.
-	 * 
-	 * @param file
-	 *            The file representing the value.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private LeafValue constructLeafValue(File file)
-			throws FilesystemAccessException {
-		LeafValue v = new LeafValue();
-		v.fileName = file.getFullName();
-		v.byteLength = file.getSize();
-		try {
-			byte[] head = file.getContents(0, 1024);
-			v.contentType = getMimeType(new ByteArrayInputStream(head));
-		} catch (Exception e) {
-			v.contentType = APPLICATION_OCTET_STREAM_TYPE.toString();
-		}
-		return v;
-	}
-
-	/**
-	 * Build a description of an error value.
-	 * 
-	 * @param file
-	 *            The file representing the error.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private ErrorValue constructErrorValue(File file)
-			throws FilesystemAccessException {
-		ErrorValue v = new ErrorValue();
-		v.fileName = file.getFullName();
-		v.byteLength = file.getSize();
-		return v;
-	}
-
-	/**
-	 * Build a description of a list value.
-	 * 
-	 * @param dir
-	 *            The directory representing the list.
-	 * @param ub
-	 *            The factory for URIs.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private ListValue constructListValue(Directory dir, UriBuilder ub)
-			throws FilesystemAccessException {
-		ListValue v = new ListValue();
-		v.length = 0;
-		Set<DirectoryEntry> contents = new HashSet<>(dir.getContents());
-		Iterator<DirectoryEntry> it = contents.iterator();
-		while (it.hasNext())
-			if (!it.next().getName().matches("^[0-9]+([.].*)?$"))
-				it.remove();
-		for (int i = 1; !contents.isEmpty(); i++) {
-			String exact = Integer.toString(i);
-			AbstractValue subval = constructValue(contents, ub, exact);
-			v.contents.add(subval);
-			if (!(subval instanceof AbsentValue)) {
-				v.length = i;
-				String pfx = i + ".";
-				for (DirectoryEntry de : contents)
-					if (de.getName().equals(exact)
-							|| de.getName().startsWith(pfx)) {
-						contents.remove(de);
-						break;
-					}
-			}
-		}
-		return v;
-	}
-
-	/**
-	 * Build a value description.
-	 * 
-	 * @param parentContents
-	 *            The contents of the parent directory.
-	 * @param ub
-	 *            The factory for URIs.
-	 * @param name
-	 *            The name of the value's file/directory representative.
-	 * @return A value descriptor.
-	 * @throws FilesystemAccessException
-	 *             If anything goes wrong.
-	 */
-	private AbstractValue constructValue(
-			Collection<DirectoryEntry> parentContents, UriBuilder ub,
-			String name) throws FilesystemAccessException {
-		String error = name + ".error";
-		String prefix = name + ".";
-		for (DirectoryEntry entry : parentContents) {
-			AbstractValue av;
-			if (entry.getName().equals(error) && entry instanceof File) {
-				av = constructErrorValue((File) entry);
-			} else if (!entry.getName().equals(name)
-					&& !entry.getName().startsWith(prefix))
-				continue;
-			else if (entry instanceof File)
-				av = constructLeafValue((File) entry);
-			else
-				av = constructListValue((Directory) entry, ub);
-			String fullPath = entry.getFullName().replaceFirst("^/", "");
-			av.href = ub.clone().path(fullPath).build();
-			return av;
-		}
-		return new AbsentValue();
-	}
-
-	/**
-	 * Construct a description of the outputs of a workflow run.
-	 * 
-	 * @param run
-	 *            The workflow run whose outputs are to be described.
-	 * @param ui
-	 *            The origin for URIs.
-	 * @return The description, which can be serialized to XML.
-	 * @throws FilesystemAccessException
-	 *             If something goes wrong reading the directories.
-	 * @throws NoDirectoryEntryException
-	 *             If something goes wrong reading the directories.
-	 */
-	public OutputDescription makeOutputDescriptor(TavernaRun run, UriInfo ui)
-			throws FilesystemAccessException, NoDirectoryEntryException {
-		OutputDescription descriptor = new OutputDescription();
-		try {
-			UriBuilder ub = getRunUriBuilder(run, ui);
-			Workflow dataflow = fillInFromWorkflow(run, ub, descriptor);
-			Collection<DirectoryEntry> outs = null;
-			ub = ub.path("wd/{path}");
-			for (OutputWorkflowPort output : dataflow.getOutputPorts()) {
-				OutputPort p = descriptor.addPort(output.getName());
-				if (run.getOutputBaclavaFile() == null) {
-					if (outs == null)
-						outs = fileUtils.getDirectory(run, "out").getContents();
-					p.output = constructValue(outs, ub, p.name);
-					p.depth = computeDepth(p.output);
-				}
-			}
-		} catch (IOException e) {
-			log.info("failure in conversion to .scufl2", e);
-		}
-		return descriptor;
-	}
-
-	private UriBuilder getRunUriBuilder(TavernaRun run, UriInfo ui) {
-		if (ui == null)
-			return secure(uriBuilderFactory.getRunUriBuilder(run));
-		else
-			return secure(fromUri(ui.getAbsolutePath().toString()
-					.replaceAll("/(out|in)put/?$", "")));
-	}
-
-	/**
-	 * Constructs input descriptions.
-	 * 
-	 * @param run
-	 *            The run to build for.
-	 * @param ui
-	 *            The mechanism for building URIs.
-	 * @return The description of the <i>expected</i> inputs of the run.
-	 */
-	public InputDescription makeInputDescriptor(TavernaRun run, UriInfo ui) {
-		InputDescription desc = new InputDescription();
-		try {
-			UriBuilder ub = getRunUriBuilder(run, ui);
-			Workflow workflow = fillInFromWorkflow(run, ub, desc);
-			ub = ub.path("input/{name}");
-			for (InputWorkflowPort port : workflow.getInputPorts()) {
-				InputPort in = desc.addPort(port.getName());
-				in.href = ub.build(in.name);
-				try {
-					in.depth = port.getDepth();
-				} catch (NumberFormatException ex) {
-					in.depth = null;
-				}
-			}
-		} catch (IOException e) {
-			log.info("failure in conversion to .scufl2", e);
-		}
-		return desc;
-	}
-}


[28/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js b/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
deleted file mode 100644
index 7835454..0000000
--- a/server-webapp/src/main/resources/static/jquery-ui-1.8.23.custom.min.js
+++ /dev/null
@@ -1,125 +0,0 @@
-/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.core.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number
 "?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelectio
 n:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.cre
 atePseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScr
 oll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.widget.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e
 ].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(
 this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||
 c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.mouse.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.del
 ay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this.
 _mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.position.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),
 n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left
 )},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.
 curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuer
 y);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.draggable.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return thi
 s.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),rel
 ative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!
 this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle
 ||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){thi
 s.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop")
 ,10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|wind
 ow|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="abs
 olute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h
 =[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version
 <526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.23"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(
 this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g
 =b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=
 this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")
 ),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensit
 ivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.pu
 sh({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left
 :0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{st
 art:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.droppable.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=
 a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;r
 eturn this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.23"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.lef
 t,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.lengt
 h;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.opt
 ions.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.resizable.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data(
 "resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne
 ,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseov
 er(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCaptu
 re:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalM
 ousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigg
 er("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.mi
 nHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=thi
 s.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borde
 rLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSiz
 e.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:thi
 s.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.23"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?[
 "width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),1
 0),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i
 ,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d
 .sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.
 originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.
 width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.selectable.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mou
 seStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unsele
 cting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selec
 ting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.23"})})
 (jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.sortable.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return thi
 s},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset
 (),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIn
 dex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scro
 llParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollL
 eft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseS
 top:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return 
 this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top
 ,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.c
 lick.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options
 .items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=
 a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.con
 tainers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft
 ")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui
 .contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]
 ),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.cont
 ains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}}
 ,_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("bo
 rderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d
 )}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click
 .top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling)
 ,this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._u
 iHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._t
 rigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.23"})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
-* https://github.com/jquery/jquery-ui
-* Includes: jquery.ui.accordion.js
-* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
-(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this)
 .removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("
 tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex
 "),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target

<TRUNCATED>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/server-webapp/src/main/resources/static/t2cogs.png
----------------------------------------------------------------------
diff --git a/server-webapp/src/main/resources/static/t2cogs.png b/server-webapp/src/main/resources/static/t2cogs.png
deleted file mode 100644
index a93b3bd..0000000
Binary files a/server-webapp/src/main/resources/static/t2cogs.png and /dev/null differ


[10/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
new file mode 100644
index 0000000..a1ac04a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimeLogger.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.String.format;
+import static java.lang.System.nanoTime;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.taverna.server.master.TavernaServer.JMX_ROOT;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.commons.logging.Log;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.jmx.export.annotation.ManagedAttribute;
+import org.springframework.jmx.export.annotation.ManagedResource;
+import org.taverna.server.master.common.version.Version;
+
+/**
+ * This class is responsible for timing all invocations of publicly-exposed
+ * methods of the webapp. It's connected to the webapp through an AspectJ-style
+ * pointcut that targets a custom annotation.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+@ManagedResource(objectName = JMX_ROOT + "PerformanceMonitor", description = "The performance monitor for Taverna Server "
+		+ Version.JAVA
+		+ ". Writes to application log using the category 'Taverna.Server.Performance'.")
+public class CallTimeLogger {
+	private long threshold = 4000000;
+	private Log log = getLog("Taverna.Server.Performance");
+
+	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
+	public long getThreshold() {
+		return threshold;
+	}
+
+	@ManagedAttribute(description = "Threshold beneath which monitored call times are not logged. In nanoseconds.")
+	public void setThreshold(long threshold) {
+		this.threshold = threshold;
+	}
+
+	/**
+	 * The timer for this aspect. The wrapped invocation will be timed, and a
+	 * log message written if the configured threshold is exceeded.
+	 * 
+	 * @param call
+	 *            The call being wrapped.
+	 * @return The result of the call.
+	 * @throws Throwable
+	 *             If anything goes wrong with the wrapped call.
+	 * @see System#nanoTime()
+	 */
+	@Around("@annotation(org.taverna.server.master.utils.CallTimeLogger.PerfLogged)")
+	public Object time(ProceedingJoinPoint call) throws Throwable {
+		long fore = nanoTime();
+		try {
+			return call.proceed();
+		} finally {
+			long aft = nanoTime();
+			long elapsed = aft - fore;
+			if (elapsed > threshold)
+				log.info(format("call to %s took %.3fms", call.toShortString(),
+						elapsed / 1000000.0));
+		}
+	}
+
+	/**
+	 * Mark methods that should be counted by the invocation counter.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Retention(RUNTIME)
+	@Documented
+	@Target(METHOD)
+	public static @interface PerfLogged {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
new file mode 100644
index 0000000..aead6fa
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CallTimingFilter.java
@@ -0,0 +1,65 @@
+/**
+ * 
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.String.format;
+import static java.lang.System.nanoTime;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Logs the time it takes to service HTTP calls into Taverna Server.
+ * <p>
+ * This class is currently not used.
+ * 
+ * @author Donal Fellows
+ */
+public class CallTimingFilter implements Filter {
+	private Log log;
+	private String name;
+
+	@Override
+	public void init(FilterConfig filterConfig) throws ServletException {
+		log = getLog("Taverna.Server.Performance");
+		name = filterConfig.getInitParameter("name");
+	}
+
+	@Override
+	public void doFilter(ServletRequest request, ServletResponse response,
+			FilterChain chain) throws IOException, ServletException {
+		if (request instanceof HttpServletRequest)
+			doFilter((HttpServletRequest) request,
+					(HttpServletResponse) response, chain);
+		else
+			chain.doFilter(request, response);
+	}
+
+	public void doFilter(HttpServletRequest request,
+			HttpServletResponse response, FilterChain chain)
+			throws IOException, ServletException {
+		long start = nanoTime();
+		chain.doFilter(request, response);
+		long elapsedTime = nanoTime() - start;
+		log.info(format("%s call to %s %s took %.3fms", name,
+				request.getMethod(), request.getRequestURI(),
+				elapsedTime / 1000000.0));
+	}
+
+	@Override
+	public void destroy() {
+		log = null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
new file mode 100644
index 0000000..54b0420
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CapabilityLister.java
@@ -0,0 +1,44 @@
+package org.taverna.server.master.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import javax.annotation.PostConstruct;
+
+import org.taverna.server.master.common.Capability;
+
+/**
+ * Utility for listing the capabilities supported by this Taverna Server
+ * installation.
+ * 
+ * @author Donal Fellows
+ */
+public class CapabilityLister {
+	public static final String CAPABILITY_RESOURCE_FILE = "/capabilities.properties";
+	private Properties properties = new Properties();
+
+	@PostConstruct
+	void loadCapabilities() throws IOException {
+		try (InputStream is = getClass().getResourceAsStream(
+				CAPABILITY_RESOURCE_FILE)) {
+			if (is != null)
+				properties.load(is);
+		}
+	}
+
+	public List<Capability> getCapabilities() {
+		List<Capability> caps = new ArrayList<>();
+		for (Entry<Object, Object> entry : properties.entrySet()) {
+			Capability c = new Capability();
+			c.capability = URI.create(entry.getKey().toString());
+			c.version = entry.getValue().toString();
+			caps.add(c);
+		}
+		return caps;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
new file mode 100644
index 0000000..c27502f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/CertificateChainFetcher.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableList;
+
+import java.io.IOException;
+import java.net.URI;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import javax.xml.ws.Holder;
+
+/**
+ * Obtains the certificate chain for an arbitrary SSL service. Maintains a
+ * cache.
+ * 
+ * @author Donal Fellows
+ */
+public class CertificateChainFetcher {
+	public String getProtocol() {
+		return protocol;
+	}
+
+	public void setProtocol(String protocol) {
+		this.protocol = protocol;
+	}
+
+	public String getKeystoreType() {
+		return keystoreType;
+	}
+
+	public void setKeystoreType(String keystoreType) {
+		this.keystoreType = keystoreType;
+	}
+
+	public String getAlgorithm() {
+		return algorithm;
+	}
+
+	public void setAlgorithm(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+	public int getTimeout() {
+		return timeout;
+	}
+
+	public void setTimeout(int timeout) {
+		this.timeout = timeout;
+	}
+
+	public void setSecure(boolean secure) {
+		this.secure = secure;
+	}
+
+	private boolean secure = true;
+	private String protocol = "TLS";
+	private String keystoreType = KeyStore.getDefaultType();
+	private String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+	private int timeout = 10000;
+
+	/**
+	 * Get the certificate chain for a service.
+	 * 
+	 * @param host
+	 *            The host (name or IP address) to contact the service on.
+	 * @param port
+	 *            The port to contact the service on.
+	 * @return The certificate chain, or <tt>null</tt> if no credentials are
+	 *         available.
+	 * @throws NoSuchAlgorithmException
+	 *             If the trust manager cannot be set up because of algorithm
+	 *             problems.
+	 * @throws KeyStoreException
+	 *             If the trust manager cannot be set up because of problems
+	 *             with the keystore type.
+	 * @throws CertificateException
+	 *             If a bad certificate is present in the default keystore;
+	 *             <i>should be impossible</i>.
+	 * @throws IOException
+	 *             If problems happen when trying to contact the service.
+	 * @throws KeyManagementException
+	 *             If the SSL context can't have its special context manager
+	 *             installed.
+	 */
+	private X509Certificate[] getCertificateChainForService(String host,
+			int port) throws NoSuchAlgorithmException, KeyStoreException,
+			CertificateException, IOException, KeyManagementException {
+		KeyStore ks = KeyStore.getInstance(keystoreType);
+		SSLContext context = SSLContext.getInstance(protocol);
+		TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+		ks.load(null, null);
+		tmf.init(ks);
+		final Holder<X509Certificate[]> chain = new Holder<>();
+		final X509TrustManager defaultTrustManager = (X509TrustManager) tmf
+				.getTrustManagers()[0];
+		context.init(null, new TrustManager[] { new X509TrustManager() {
+			@Override
+			public void checkClientTrusted(X509Certificate[] clientChain,
+					String authType) throws CertificateException {
+				throw new UnsupportedOperationException();
+			}
+
+			@Override
+			public void checkServerTrusted(X509Certificate[] serverChain,
+					String authType) throws CertificateException {
+				chain.value = serverChain;
+				defaultTrustManager.checkServerTrusted(serverChain, authType);
+			}
+
+			@Override
+			public X509Certificate[] getAcceptedIssuers() {
+				throw new UnsupportedOperationException();
+			}
+		} }, null);
+		SSLSocketFactory factory = context.getSocketFactory();
+		try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
+			socket.setSoTimeout(timeout);
+			socket.startHandshake();
+		} catch (SSLException e) {
+			// Ignore
+		}
+		return chain.value;
+	}
+
+	private Map<URI, List<X509Certificate>> cache = new HashMap<>();
+
+	/**
+	 * Gets the certificate chain for a service identified by URI.
+	 * 
+	 * @param uri
+	 *            The URI of the (secure) service to identify.
+	 * @return The certificate chain. Will be <tt>null</tt> if the service is
+	 *         not secure.
+	 * @throws IOException
+	 *             If the service is unreachable or other connection problems
+	 *             occur.
+	 * @throws GeneralSecurityException
+	 *             If any of a number of security-related problems occur, such
+	 *             as an inability to match detailed security protocols.
+	 */
+	public List<X509Certificate> getTrustsForURI(URI uri) throws IOException,
+			GeneralSecurityException {
+		if (!secure)
+			return null;
+		synchronized (this) {
+			if (!cache.containsKey(uri)) {
+				int port = uri.getPort();
+				if (port == -1)
+					switch (uri.getScheme()) {
+					case "http":
+						port = 80;
+						break;
+					case "https":
+						port = 443;
+						break;
+					default:
+						return null;
+					}
+				X509Certificate[] chain = getCertificateChainForService(
+						uri.getHost(), port);
+				if (chain != null)
+					cache.put(uri, unmodifiableList(asList(chain)));
+				else
+					cache.put(uri, null);
+			}
+			return cache.get(uri);
+		}
+	}
+
+	/**
+	 * Flushes the cache.
+	 */
+	public void flushCache() {
+		synchronized (this) {
+			cache.clear();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
new file mode 100644
index 0000000..884ff94
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/Contextualizer.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.UriInfo;
+
+import org.springframework.web.context.ServletContextAware;
+import org.taverna.server.master.common.version.Version;
+
+/**
+ * Convert a string (URL, etc) to a version that is contextualized to the
+ * web-application.
+ * 
+ * @author Donal Fellows
+ */
+public class Contextualizer implements ServletContextAware {
+	static final String ROOT_PLACEHOLDER = "%{WEBAPPROOT}";
+	static final String VERSION_PLACEHOLDER = "%{VERSION}";
+	static final String BASE_PLACEHOLDER = "%{BASEURL}";
+
+	/**
+	 * Apply the contextualization operation. This consists of replacing the
+	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the webapp.
+	 * 
+	 * @param input
+	 *            the string to contextualize
+	 * @return the contextualized string
+	 */
+	public String contextualize(String input) {
+		// Hack to work around bizarre CXF bug
+		String path = context.getRealPath("/").replace("%2D", "-");
+		return input.replace(ROOT_PLACEHOLDER, path).replace(
+				VERSION_PLACEHOLDER, Version.JAVA);
+	}
+
+	/**
+	 * Apply the contextualization operation. This consists of replacing the
+	 * string <tt>{@value #ROOT_PLACEHOLDER}</tt> with the real root of the
+	 * webapp.
+	 * 
+	 * @param ui
+	 *            Where to get information about the URL used to access the
+	 *            webapp.
+	 * @param input
+	 *            the string to contextualize
+	 * @return the contextualized string
+	 */
+	public String contextualize(UriInfo ui, String input) {
+		// Hack to work around bizarre CXF bug
+		String baseuri = ui.getBaseUri().toString().replace("%2D", "-");
+		if (baseuri.endsWith("/"))
+			baseuri = baseuri.substring(0, baseuri.length() - 1);
+		return contextualize(input).replace(BASE_PLACEHOLDER, baseuri);
+	}
+
+	private ServletContext context;
+
+	@Override
+	public void setServletContext(ServletContext servletContext) {
+		context = servletContext;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
new file mode 100644
index 0000000..f8b39e3
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/DerbyUtils.java
@@ -0,0 +1,68 @@
+package org.taverna.server.master.utils;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Utility class, used to make Derby less broken.
+ * 
+ * @see <a
+ *      href="http://stackoverflow.com/questions/1004327/getting-rid-of-derby-log">
+ *      Getting rid of derby.log </a>
+ * @see <a
+ *      href="http://stackoverflow.com/questions/3339736/set-system-property-with-spring-configuration-file">
+ *      Set system property with Spring configuration file </a>
+ */
+public class DerbyUtils {
+	/**
+	 * A writer that channels things on to the log.
+	 */
+	public static final Writer TO_LOG = new DBLog();
+	// Hack
+	public static final Writer DEV_NULL = TO_LOG;
+}
+
+class DBLog extends Writer {
+	private Log log = LogFactory.getLog("Taverna.Server.Database");
+	private StringBuilder sb = new StringBuilder();
+	private boolean closed = false;
+
+	@Override
+	public void write(char[] cbuf, int off, int len) throws IOException {
+		if (closed)
+			throw new EOFException();
+		if (!log.isInfoEnabled())
+			return;
+		sb.append(cbuf, off, len);
+		while (!closed) {
+			int idx = sb.indexOf("\n"), realIdx = idx;
+			if (idx < 0)
+				break;
+			char ch;
+			while (idx > 0 && ((ch = sb.charAt(idx - 1)) == '\r' || ch == ' ' || ch == '\t'))
+				idx--;
+			if (idx > 0)
+				log.info(sb.substring(0, idx));
+			sb.delete(0, realIdx + 1);
+		}
+	}
+
+	@Override
+	public void flush() throws IOException {
+		if (sb.length() > 0) {
+			log.info(sb.toString());
+			sb = new StringBuilder();
+		}
+	}
+
+	@Override
+	public void close() throws IOException {
+		flush();
+		closed = true;
+		sb = null;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
new file mode 100644
index 0000000..19299e2
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FilenameUtils.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import java.util.List;
+
+import javax.ws.rs.core.PathSegment;
+
+import org.taverna.server.master.common.DirEntryReference;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+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.TavernaRun;
+
+/**
+ * Utility functions for getting entries from directories.
+ * 
+ * @author Donal Fellows
+ */
+public class FilenameUtils {
+	private static final String TYPE_ERROR = "trying to take subdirectory of file";
+	private static final String NO_FILE = "no such directory entry";
+	private static final String NOT_A_FILE = "not a file";
+	private static final String NOT_A_DIR = "not a directory";
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the directory entry to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path; an empty path will retrieve the working directory handle
+	 *         itself.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (name == null || name.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		// Must be nested loops; avoids problems with %-encoded "/" chars
+		for (String bit : name.split("/")) {
+			if (mustBeLast)
+				throw new FilesystemAccessException(TYPE_ERROR);
+			found = getEntryFromDir(bit, dir);
+			dir = null;
+			if (found instanceof Directory) {
+				dir = (Directory) found;
+				mustBeLast = false;
+			} else
+				mustBeLast = true;
+		}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The path segments describing what to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path; an empty path will retrieve the working directory handle
+	 *         itself.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, List<PathSegment> d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (d == null || d.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		// Must be nested loops; avoids problems with %-encoded "/" chars
+		for (PathSegment segment : d)
+			for (String bit : segment.getPath().split("/")) {
+				if (mustBeLast)
+					throw new FilesystemAccessException(TYPE_ERROR);
+				found = getEntryFromDir(bit, dir);
+				dir = null;
+				if (found instanceof Directory) {
+					dir = (Directory) found;
+					mustBeLast = false;
+				} else
+					mustBeLast = true;
+			}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The directory entry whose name is equal to the last part of the
+	 *         path in the directory reference; an empty path will retrieve the
+	 *         working directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public DirectoryEntry getDirEntry(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		Directory dir = run.getWorkingDirectory();
+		if (d == null || d.path == null || d.path.isEmpty())
+			return dir;
+		DirectoryEntry found = dir;
+		boolean mustBeLast = false;
+
+		for (String bit : d.path.split("/")) {
+			if (mustBeLast)
+				throw new FilesystemAccessException(TYPE_ERROR);
+			found = getEntryFromDir(bit, dir);
+			dir = null;
+			if (found instanceof Directory) {
+				dir = (Directory) found;
+				mustBeLast = false;
+			} else
+				mustBeLast = true;
+		}
+		return found;
+	}
+
+	/**
+	 * Get a named directory entry from a directory.
+	 * 
+	 * @param name
+	 *            The name of the entry; must be "<tt>/</tt>"-free.
+	 * @param dir
+	 *            The directory to look in.
+	 * @return The directory entry whose name is equal to the given name.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable.
+	 */
+	private DirectoryEntry getEntryFromDir(String name, Directory dir)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		if (dir == null)
+			throw new FilesystemAccessException(NO_FILE);
+		for (DirectoryEntry entry : dir.getContents())
+			if (entry.getName().equals(name))
+				return entry;
+		throw new NoDirectoryEntryException(NO_FILE);
+	}
+
+	/**
+	 * Get a named directory from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The directory whose name is equal to the last part of the path in
+	 *         the directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable, or if the
+	 *             name doesn't refer to a directory.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public Directory getDirectory(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, d);
+		if (dirEntry instanceof Directory)
+			return (Directory) dirEntry;
+		throw new FilesystemAccessException(NOT_A_DIR);
+	}
+
+	/**
+	 * Get a named directory from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the directory to look up.
+	 * @return The directory.
+	 * @throws FilesystemAccessException
+	 *             If the directory isn't specified or isn't readable, or if the
+	 *             name doesn't refer to a directory.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public Directory getDirectory(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, name);
+		if (dirEntry instanceof Directory)
+			return (Directory) dirEntry;
+		throw new FilesystemAccessException(NOT_A_DIR);
+	}
+
+	/**
+	 * Get a named file from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param d
+	 *            The directory reference describing what to look up.
+	 * @return The file whose name is equal to the last part of the path in the
+	 *         directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the file isn't specified or isn't readable, or if the name
+	 *             doesn't refer to a file.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public File getFile(TavernaRun run, DirEntryReference d)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, d);
+		if (dirEntry instanceof File)
+			return (File) dirEntry;
+		throw new FilesystemAccessException(NOT_A_FILE);
+	}
+
+	/**
+	 * Get a named file from a workflow run.
+	 * 
+	 * @param run
+	 *            The run whose working directory is to be used as the root of
+	 *            the search.
+	 * @param name
+	 *            The name of the file to look up.
+	 * @return The file whose name is equal to the last part of the path in the
+	 *         directory reference; an empty path will retrieve the working
+	 *         directory handle itself.
+	 * @throws FilesystemAccessException
+	 *             If the file isn't specified or isn't readable, or if the name
+	 *             doesn't refer to a file.
+	 * @throws NoDirectoryEntryException
+	 *             If there is no such entry.
+	 */
+	public File getFile(TavernaRun run, String name)
+			throws FilesystemAccessException, NoDirectoryEntryException {
+		DirectoryEntry dirEntry = getDirEntry(run, name);
+		if (dirEntry instanceof File)
+			return (File) dirEntry;
+		throw new FilesystemAccessException(NOT_A_FILE);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
new file mode 100644
index 0000000..ff52e81
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/FlushThreadLocalCacheInterceptor.java
@@ -0,0 +1,18 @@
+package org.taverna.server.master.utils;
+
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+
+public class FlushThreadLocalCacheInterceptor extends
+		AbstractPhaseInterceptor<Message> {
+	public FlushThreadLocalCacheInterceptor() {
+		super(Phase.USER_LOGICAL_ENDING);
+	}
+
+	@Override
+	public void handleMessage(Message message) {
+		ProviderFactory.getInstance(message).clearThreadLocalProxies();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
new file mode 100644
index 0000000..55a260b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/InvocationCounter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+
+/**
+ * This class is responsible for counting all invocations of publicly-exposed
+ * methods of the webapp. It's connected to the webapp primarily through an
+ * AspectJ-style pointcut.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+public class InvocationCounter {
+	private int count;
+
+	@Before("@annotation(org.taverna.server.master.utils.InvocationCounter.CallCounted)")
+	public synchronized void count() {
+		count++;
+	}
+
+	public synchronized int getCount() {
+		return count;
+	}
+
+	/**
+	 * Mark methods that should be counted by the invocation counter.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Retention(RUNTIME)
+	@Documented
+	@Target(METHOD)
+	public static @interface CallCounted {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
new file mode 100644
index 0000000..252e316
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JCECheck.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.Integer.MAX_VALUE;
+import static javax.crypto.Cipher.getMaxAllowedKeyLength;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Trivial bean that checks for whether the JCE policy files that allow
+ * unlimited strength security are present, and warns in the log if not.
+ * 
+ * @author Donal Fellows
+ */
+public class JCECheck {
+	/**
+	 * Write a message to the log that says whether an unlimited strength
+	 * {@linkplain #Cipher cipher} is present. This is the official proxy for
+	 * whether the unlimited strength JCE policy files have been installed; if
+	 * absent, the message is logged as a warning, otherwise it is just
+	 * informational.
+	 */
+	@PostConstruct
+	public void checkForUnlimitedJCE() {
+		Log log = getLog("Taverna.Server.Utils");
+
+		try {
+			if (getMaxAllowedKeyLength("AES") < MAX_VALUE)
+				log.warn("maximum key length very short; unlimited "
+						+ "strength JCE policy files maybe missing");
+			else
+				log.info("unlimited strength JCE policy in place");
+		} catch (GeneralSecurityException e) {
+			log.warn("problem computing key length limits!", e);
+		}
+	}
+
+	/**
+	 * @return Whether the unlimited strength JCE policy files are present (or
+	 *         rather whether an unlimited strength {@linkplain #Cipher cipher}
+	 *         is permitted).
+	 */
+	public boolean isUnlimitedStrength() {
+		try {
+			return getMaxAllowedKeyLength("AES") == MAX_VALUE;
+		} catch (NoSuchAlgorithmException e) {
+			return false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
new file mode 100644
index 0000000..ba9ec81
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/JDOSupport.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.WeakHashMap;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
+import javax.jdo.JDOException;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.apache.commons.logging.Log;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Simple support class that wraps up and provides access to the correct parts
+ * of JDO.
+ * 
+ * @author Donal Fellows
+ * 
+ * @param &lt;T&gt; The context class that the subclass will be working with.
+ */
+public abstract class JDOSupport<T> {
+	private Class<T> contextClass;
+	private PersistenceManagerBuilder pmb;
+
+	/**
+	 * Instantiate this class, supplying it a handle to the class that will be
+	 * used to provide context for queries and accesses.
+	 * 
+	 * @param contextClass
+	 *            Must match the type parameter to the class itself.
+	 */
+	protected JDOSupport(@Nonnull Class<T> contextClass) {
+		this.contextClass = contextClass;
+	}
+
+	/**
+	 * @param persistenceManagerBuilder
+	 *            The JDO engine to use for managing persistence.
+	 */
+	@Required
+	public void setPersistenceManagerBuilder(
+			PersistenceManagerBuilder persistenceManagerBuilder) {
+		pmb = persistenceManagerBuilder;
+	}
+
+	private PersistenceManager pm() {
+		if (isPersistent())
+			return pmb.getPersistenceManager();
+		return null;
+	}
+
+	/**
+	 * Has this class actually been configured with a persistence manager by
+	 * Spring?
+	 * 
+	 * @return Whether there is a persistence manager installed.
+	 */
+	protected boolean isPersistent() {
+		return pmb != null;
+	}
+
+	/**
+	 * Get an instance of a query in JDOQL.
+	 * 
+	 * @param filter
+	 *            The filter part of the query.
+	 * @return The query, which should be executed to retrieve the results.
+	 */
+	@Nonnull
+	protected Query query(@Nonnull String filter) {
+		return pm().newQuery(contextClass, filter);
+	}
+
+	/**
+	 * Get an instance of a named query attached to the context class (as an
+	 * annotation).
+	 * 
+	 * @param name
+	 *            The name of the query.
+	 * @return The query, which should be executed to retrieve the results.
+	 * @see javax.jdo.annotations.Query
+	 */
+	@Nonnull
+	protected Query namedQuery(@Nonnull String name) {
+		return pm().newNamedQuery(contextClass, name);
+	}
+
+	/**
+	 * Make an instance of the context class persist in the database. It's
+	 * identity must not already exist.
+	 * 
+	 * @param value
+	 *            The instance to persist.
+	 * @return The persistence-coupled instance.
+	 */
+	@Nullable
+	protected T persist(@Nullable T value) {
+		if (value == null)
+			return null;
+		return pm().makePersistent(value);
+	}
+
+	/**
+	 * Make a non-persistent (i.e., will hold its value past the end of the
+	 * transaction) copy of a persistence-coupled instance of the context class.
+	 * 
+	 * @param value
+	 *            The value to decouple.
+	 * @return The non-persistent copy.
+	 */
+	@Nullable
+	protected T detach(@Nullable T value) {
+		if (value == null)
+			return null;
+		return pm().detachCopy(value);
+	}
+
+	/**
+	 * Look up an instance of the context class by its identity.
+	 * 
+	 * @param id
+	 *            The identity of the object.
+	 * @return The instance, which is persistence-coupled.
+	 */
+	@Nullable
+	protected T getById(Object id) {
+		try {
+			return pm().getObjectById(contextClass, id);
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Delete a persistence-coupled instance of the context class.
+	 * 
+	 * @param value
+	 *            The value to delete.
+	 */
+	protected void delete(@Nullable T value) {
+		if (value != null)
+			pm().deletePersistent(value);
+	}
+
+	/**
+	 * Manages integration of JDO transactions with Spring.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Aspect
+	public static class TransactionAspect {
+		private Object lock = new Object();
+		private Log log = getLog("Taverna.Server.Utils");
+		private volatile int txid;
+
+		@Around(value = "@annotation(org.taverna.server.master.utils.JDOSupport.WithinSingleTransaction) && target(support)", argNames = "support")
+		Object applyTransaction(ProceedingJoinPoint pjp, JDOSupport<?> support)
+				throws Throwable {
+			synchronized (lock) {
+				PersistenceManager pm = support.pm();
+				int id = ++txid;
+				Transaction tx = (pm == null) ? null : pm.currentTransaction();
+				if (tx != null && tx.isActive())
+					tx = null;
+				if (tx != null) {
+					if (log.isDebugEnabled())
+						log.debug("starting transaction #" + id);
+					tx.begin();
+				}
+				try {
+					Object result = pjp.proceed();
+					if (tx != null) {
+						tx.commit();
+						if (log.isDebugEnabled())
+							log.debug("committed transaction #" + id);
+					}
+					tx = null;
+					return result;
+				} catch (Throwable t) {
+					try {
+						if (tx != null) {
+							tx.rollback();
+							if (log.isDebugEnabled())
+								log.debug("rolled back transaction #" + id);
+						}
+					} catch (JDOException e) {
+						log.warn("rollback failed unexpectedly", e);
+					}
+					throw t;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Mark a method (of a subclass of {@link JDOSupport}) as having a
+	 * transaction wrapped around it. The transactions are managed correctly in
+	 * the multi-threaded case.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@Target(METHOD)
+	@Retention(RUNTIME)
+	@Documented
+	public @interface WithinSingleTransaction {
+	}
+
+	/**
+	 * Manages {@linkplain PersistenceManager persistence managers} in a way
+	 * that doesn't cause problems when the web application is unloaded.
+	 * 
+	 * @author Donal Fellows
+	 */
+	public static class PersistenceManagerBuilder {
+		private PersistenceManagerFactory pmf;
+		private WeakHashMap<Thread, PersistenceManager> cache = new WeakHashMap<>();
+
+		/**
+		 * @param persistenceManagerFactory
+		 *            The JDO engine to use for managing persistence.
+		 */
+		@Required
+		public void setPersistenceManagerFactory(
+				PersistenceManagerFactory persistenceManagerFactory) {
+			pmf = persistenceManagerFactory;
+		}
+
+		@Nonnull
+		public PersistenceManager getPersistenceManager() {
+			if (cache == null)
+				return pmf.getPersistenceManager();
+			Thread t = Thread.currentThread();
+			PersistenceManager pm = cache.get(t);
+			if (pm == null && pmf != null) {
+				pm = pmf.getPersistenceManager();
+				cache.put(t, pm);
+			}
+			return pm;
+		}
+
+		@PreDestroy
+		void clearThreadCache() {
+			WeakHashMap<Thread, PersistenceManager> cache = this.cache;
+			this.cache = null;
+			for (PersistenceManager pm : cache.values())
+				if (pm != null)
+					pm.close();
+			cache.clear();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
new file mode 100644
index 0000000..a8aa937
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/LoggingDerbyAdapter.java
@@ -0,0 +1,138 @@
+package org.taverna.server.master.utils;
+
+import static java.lang.System.currentTimeMillis;
+import static java.lang.Thread.sleep;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.sql.DatabaseMetaData;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.datanucleus.store.rdbms.adapter.DerbyAdapter;
+import org.datanucleus.store.rdbms.identifier.IdentifierFactory;
+import org.datanucleus.store.rdbms.key.CandidateKey;
+import org.datanucleus.store.rdbms.key.ForeignKey;
+import org.datanucleus.store.rdbms.key.Index;
+import org.datanucleus.store.rdbms.key.PrimaryKey;
+import org.datanucleus.store.rdbms.sql.SQLTable;
+import org.datanucleus.store.rdbms.table.Column;
+import org.datanucleus.store.rdbms.table.Table;
+import org.datanucleus.store.rdbms.table.TableImpl;
+import org.datanucleus.store.rdbms.table.ViewImpl;
+
+/**
+ * Evil hack to allow logging of the DDL spat out to Derby.
+ * 
+ * @author Donal Fellows
+ */
+public class LoggingDerbyAdapter extends DerbyAdapter {
+	Log log = getLog("Taverna.Server.SQL");
+
+	private StringBuilder ddl = new StringBuilder();
+	private volatile long timeout;
+	private Thread timer;
+
+	private synchronized void logDDL() {
+		if (ddl.length() > 0) {
+			log.info("Data definition language:\n" + ddl);
+			ddl.setLength(0);
+		}
+		timer = null;
+	}
+
+	private synchronized void doLog(String item) {
+		ddl.append(item);
+		if (!item.endsWith("\n"))
+			ddl.append('\n');
+		timeout = currentTimeMillis() + 5000;
+		if (timer == null)
+			timer = new OneShotThread("DDL logger timeout", new Runnable() {
+				@Override
+				public void run() {
+					try {
+						while (timeout > currentTimeMillis())
+							sleep(1000);
+					} catch (InterruptedException e) {
+						// Ignore
+					}
+					logDDL();
+				}
+			});
+	}
+
+	/**
+	 * Creates an Apache Derby adapter based on the given metadata which logs
+	 * the DDL it creates.
+	 */
+	public LoggingDerbyAdapter(DatabaseMetaData metadata) {
+		super(metadata);
+	}
+
+	@Override
+	public String getCreateTableStatement(TableImpl table, Column[] columns,
+			Properties props, IdentifierFactory factory) {
+		String statement = super.getCreateTableStatement(table, columns, props,
+				factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getCreateIndexStatement(Index index, IdentifierFactory factory) {
+		String statement = super.getCreateIndexStatement(index, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddCandidateKeyStatement(CandidateKey ck,
+			IdentifierFactory factory) {
+		String statement = super.getAddCandidateKeyStatement(ck, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddPrimaryKeyStatement(PrimaryKey pk,
+			IdentifierFactory factory) {
+		String statement = super.getAddPrimaryKeyStatement(pk, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddColumnStatement(Table table, Column col) {
+		String statement = super.getAddColumnStatement(table, col);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getAddForeignKeyStatement(ForeignKey fk,
+			IdentifierFactory factory) {
+		String statement = super.getAddForeignKeyStatement(fk, factory);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDeleteTableStatement(SQLTable tbl) {
+		String statement = super.getDeleteTableStatement(tbl);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDropTableStatement(Table table) {
+		String statement = super.getDropTableStatement(table);
+		doLog(statement);
+		return statement;
+	}
+
+	@Override
+	public String getDropViewStatement(ViewImpl view) {
+		String statement = super.getDropViewStatement(view);
+		doLog(statement);
+		return statement;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
new file mode 100644
index 0000000..68b813d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/OneShotThread.java
@@ -0,0 +1,10 @@
+package org.taverna.server.master.utils;
+
+public class OneShotThread extends Thread {
+	public OneShotThread(String name, Runnable target) {
+		super(target, name);
+		setContextClassLoader(null);
+		setDaemon(true);
+		start();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
new file mode 100644
index 0000000..a892b52
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RestUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.core.Response;
+
+/**
+ * Utilities that make it easier to write REST services.
+ * 
+ * @author Donal Fellows
+ */
+public class RestUtils {
+	/**
+	 * Generate a response to an HTTP OPTIONS request.
+	 * 
+	 * @param methods
+	 *            The state-changing methods supported, if any.
+	 * @return the required response
+	 * @see OPTIONS
+	 */
+	public static Response opt(String... methods) {
+		StringBuilder sb = new StringBuilder("GET,");
+		for (String m : methods)
+			sb.append(m).append(",");
+		sb.append("HEAD,OPTIONS");
+		return Response.ok().header("Allow", sb.toString()).entity("").build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
new file mode 100644
index 0000000..0b2d4ea
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/RuntimeExceptionWrapper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.taverna.server.master.exceptions.GeneralFailureException;
+
+/**
+ * Aspect used to convert {@linkplain RuntimeException runtime exceptions} into
+ * a form that can be nicely conveyed to the outside world as HTTP errors.
+ * 
+ * @author Donal Fellows
+ */
+@Aspect
+public class RuntimeExceptionWrapper {
+	/**
+	 * Map an unexpected exception to one that can be correctly reported as a
+	 * problem.
+	 * 
+	 * @param exn
+	 *            The runtime exception being trapped.
+	 * @throws GeneralFailureException
+	 *             The known exception type that it is mapped to.
+	 */
+	@AfterThrowing(pointcut = "execution(* org.taverna.server.master.rest..*(..)) && !bean(*Provider.*)", throwing = "exn")
+	public void wrapRuntimeException(RuntimeException exn)
+			throws GeneralFailureException {
+		// Exclude security-related exceptions
+		if (exn.getClass().getName().startsWith("org.springframework.security."))
+			return;
+		throw new GeneralFailureException(exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
new file mode 100644
index 0000000..9bbcc2f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/UsernamePrincipal.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import java.io.Serializable;
+import java.security.Principal;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * A simple serializable principal that just records the name.
+ * 
+ * @author Donal Fellows
+ */
+public class UsernamePrincipal implements Principal, Serializable {
+	private static final long serialVersionUID = 2703493248562435L;
+	public UsernamePrincipal(String username) {
+		this.name = username;
+	}
+
+	public UsernamePrincipal(Principal other) {
+		this.name = other.getName();
+	}
+
+	public UsernamePrincipal(Authentication auth) {
+		this(auth.getPrincipal());
+	}
+
+	public UsernamePrincipal(Object principal) {
+		if (principal instanceof Principal)
+			this.name = ((Principal) principal).getName();
+		else if (principal instanceof String)
+			this.name = (String) principal;
+		else if (principal instanceof UserDetails)
+			this.name = ((UserDetails) principal).getUsername();
+		else
+			this.name = principal.toString();
+	}
+
+	private String name;
+
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	@Override
+	public String toString() {
+		return "Principal<" + name + ">";
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof Principal) {
+			Principal p = (Principal) o;
+			return name.equals(p.getName());
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return name.hashCode();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
new file mode 100644
index 0000000..96cdc6d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WSDLHeadOptionsInterceptor.java
@@ -0,0 +1,65 @@
+package org.taverna.server.master.utils;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+import static org.apache.cxf.common.util.UrlUtils.parseQueryString;
+import static org.apache.cxf.message.Message.HTTP_REQUEST_METHOD;
+import static org.apache.cxf.message.Message.QUERY_STRING;
+import static org.apache.cxf.message.Message.REQUEST_URL;
+import static org.apache.cxf.phase.Phase.READ;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.cxf.binding.soap.interceptor.EndpointSelectionInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+
+
+/**
+ * Thunk for TAVSERV-293.
+ * 
+ * @author Donal Fellows (based on work by Daniel Hagen)
+ */
+public class WSDLHeadOptionsInterceptor extends
+		AbstractPhaseInterceptor<Message> {
+	public static final Log log = getLog("Taverna.Server.Utils");
+
+	public WSDLHeadOptionsInterceptor() {
+		super(READ);
+		getAfter().add(EndpointSelectionInterceptor.class.getName());
+	}
+
+	@Override
+	public void handleMessage(Message message) throws Fault {
+		String method = (String) message.get(HTTP_REQUEST_METHOD);
+		String query = (String) message.get(QUERY_STRING);
+
+		if (("HEAD".equals(method) || "OPTIONS".equals(method))
+				&& query != null && !query.trim().isEmpty()
+				&& isRecognizedQuery(query)) {
+			log.debug("adjusting message request method " + method + " for "
+					+ message.get(REQUEST_URL) + " to GET");
+			message.put(HTTP_REQUEST_METHOD, "GET");
+		}
+	}
+
+	/*
+	 * Stolen from http://permalink.gmane.org/gmane.comp.apache.cxf.user/20037
+	 * which is itself in turn stolen from
+	 * org.apache.cxf.frontend.WSDLGetInterceptor.isRecognizedQuery
+	 */
+	/**
+	 * Is this a query for WSDL or XSD relating to it?
+	 * 
+	 * @param query
+	 *            The query string to check
+	 * @return If the query is one to handle.
+	 * @see org.apache.cxf.frontend.WSDLGetInterceptor#isRecognizedQuery(Map,String,String,org.apache.cxf.service.model.EndpointInfo)
+	 *      WSDLGetInterceptor
+	 */
+	private boolean isRecognizedQuery(String query) {
+		Map<String, String> map = parseQueryString(query);
+		return map.containsKey("wsdl") || map.containsKey("xsd");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
new file mode 100644
index 0000000..03fc749
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/WebappAwareDataSource.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static java.lang.Thread.currentThread;
+import static java.sql.DriverManager.deregisterDriver;
+import static java.sql.DriverManager.getDrivers;
+import static org.taverna.server.master.utils.Contextualizer.ROOT_PLACEHOLDER;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Enumeration;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * Add some awareness of the context so that we can locate databases internally
+ * to the webapp.
+ * 
+ * @author Donal Fellows
+ */
+public class WebappAwareDataSource extends BasicDataSource {
+	Log log = LogFactory.getLog("Taverna.Server.Utils");
+	private transient boolean init;
+	private Contextualizer ctxt;
+	private String shutdownUrl;
+
+	@Required
+	public void setContextualizer(Contextualizer ctxt) {
+		this.ctxt = ctxt;
+	}
+
+	/**
+	 * A JDBC connection URL to use on shutting down the database. If not set,
+	 * do nothing special.
+	 * 
+	 * @param url
+	 */
+	public void setShutdownUrl(String url) {
+		shutdownUrl = url;
+	}
+
+	private void doInit() {
+		synchronized (this) {
+			if (!init) {
+				setDriverClassLoader(currentThread().getContextClassLoader());
+				String url = getUrl();
+				if (url.contains(ROOT_PLACEHOLDER)) {
+					String newurl = ctxt.contextualize(url);
+					setUrl(newurl);
+					log.info("mapped " + url + " to " + newurl);
+				} else {
+					log.info("did not find " + ROOT_PLACEHOLDER + " in " + url);
+				}
+				init = true;
+			}
+		}
+	}
+
+	// -=-=-=-=-=-=-=-=-=-=- HOOKS -=-=-=-=-=-=-=-=-=-=-
+
+	@Override
+	public Connection getConnection() throws SQLException {
+		doInit();
+		return super.getConnection();
+	}
+
+	@Override
+	public void setLogWriter(PrintWriter pw) throws SQLException {
+		doInit();
+		super.setLogWriter(pw);
+	}
+
+	@Override
+	public void setLoginTimeout(int num) throws SQLException {
+		doInit();
+		super.setLoginTimeout(num);
+	}
+
+	@Override
+	public PrintWriter getLogWriter() throws SQLException {
+		doInit();
+		return super.getLogWriter();
+	}
+
+	@Override
+	public int getLoginTimeout() throws SQLException {
+		doInit();
+		return super.getLoginTimeout();
+	}
+
+	@PreDestroy
+	void realClose() {
+		try {
+			close();
+		} catch (SQLException e) {
+			log.warn("problem shutting down DB connection", e);
+		}
+		try {
+			if (shutdownUrl != null)
+				DriverManager.getConnection(ctxt.contextualize(shutdownUrl));
+		} catch (SQLException e) {
+			// Expected; ignore it
+		}
+		log = null;
+		dropDriver();
+	}
+
+	private void dropDriver() {
+		Enumeration<Driver> drivers = getDrivers();
+		while (drivers.hasMoreElements()) {
+			Driver d = drivers.nextElement();
+			if (d.getClass().getClassLoader() == getDriverClassLoader()
+					&& d.getClass().getName().equals(getDriverClassName())) {
+				try {
+					deregisterDriver(d);
+				} catch (SQLException e) {
+				}
+				break;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
new file mode 100644
index 0000000..da4cff0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/X500Utils.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.utils;
+
+import static javax.security.auth.x500.X500Principal.RFC2253;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.PreDestroy;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Support class that factors out some of the messier parts of working with
+ * X.500 identities and X.509 certificates.
+ * 
+ * @author Donal Fellows
+ */
+public class X500Utils {
+	private Log log = LogFactory.getLog("Taverna.Server.Utils");
+
+	@PreDestroy
+	void closeLog() {
+		log = null;
+	}
+
+	private static final char DN_SEPARATOR = ',';
+	private static final char DN_ESCAPE = '\\';
+	private static final char DN_QUOTE = '"';
+
+	/**
+	 * Parse the DN from the Principal and extract the CN field.
+	 * 
+	 * @param id
+	 *            The identity to extract the distinguished name from.
+	 * @param fields
+	 *            The names to look at when finding the field to return. Each
+	 *            should be an upper-cased string.
+	 * @return The common-name part of the distinguished name, or the literal
+	 *         string "<tt>none</tt>" if there is no CN.
+	 */
+	public String getName(X500Principal id, String... fields) {
+		String dn = id.getName(RFC2253);
+
+		int i = 0;
+		int startIndex = 0;
+		boolean ignoreThisChar = false;
+		boolean inQuotes = false;
+		Map<String, String> tokenized = new HashMap<>();
+
+		for (i = 0; i < dn.length(); i++)
+			if (ignoreThisChar)
+				ignoreThisChar = false;
+			else if (dn.charAt(i) == DN_QUOTE)
+				inQuotes = !inQuotes;
+			else if (inQuotes)
+				continue;
+			else if (dn.charAt(i) == DN_ESCAPE)
+				ignoreThisChar = true;
+			else if ((dn.charAt(i) == DN_SEPARATOR) && !ignoreThisChar) {
+				storeDNField(tokenized, dn.substring(startIndex, i).trim()
+						.split("=", 2));
+				startIndex = i + 1;
+			}
+		if (inQuotes || ignoreThisChar)
+			log.warn("was parsing invalid DN format");
+		// Add last token - after the last delimiter
+		storeDNField(tokenized, dn.substring(startIndex).trim().split("=", 2));
+
+		for (String field : fields) {
+			String value = tokenized.get(field);
+			if (value != null)
+				return value;
+		}
+		return "none";
+	}
+
+	private void storeDNField(Map<String, String> container, String[] split) {
+		if (split == null || split.length != 2)
+			return;
+		String key = split[0].toUpperCase();
+		if (container.containsKey(key))
+			log.warn("duplicate field in DN: " + key);
+		// LATER: Should the field be de-quoted?
+		container.put(key, split[1]);
+	}
+
+	/**
+	 * Get the serial number from a certificate as a hex string.
+	 * 
+	 * @param cert
+	 *            The certificate to extract from.
+	 * @return A hex string, in upper-case.
+	 */
+	public String getSerial(X509Certificate cert) {
+		return new BigInteger(1, cert.getSerialNumber().toByteArray())
+				.toString(16).toUpperCase();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
new file mode 100644
index 0000000..612e61c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/utils/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Miscellaneous utility classes. Includes aspects that might be attached
+ * for purposes such as transaction management and invocation tracking.
+ */
+package org.taverna.server.master.utils;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
new file mode 100644
index 0000000..10b3830
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/CompletionNotifier.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+
+/**
+ * How to convert a notification about the completion of a job into a message.
+ * 
+ * @author Donal Fellows
+ */
+public interface CompletionNotifier {
+	/**
+	 * @return The name of this notifier.
+	 */
+	String getName();
+
+	/**
+	 * Called to get the content of a message that a workflow run has finished.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param run
+	 *            What run are we talking about.
+	 * @param code
+	 *            What the exit code was.
+	 * @return The plain-text content of the message.
+	 */
+	String makeCompletionMessage(String name, RemoteRunDelegate run, int code);
+
+	/**
+	 * Called to get the subject of the message to dispatch.
+	 * 
+	 * @param name
+	 *            The name of the run.
+	 * @param run
+	 *            What run are we talking about.
+	 * @param code
+	 *            What the exit code was.
+	 * @return The plain-text subject of the message.
+	 */
+	String makeMessageSubject(String name, RemoteRunDelegate run, int code);
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
new file mode 100644
index 0000000..5d0f371
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/FactoryBean.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import org.taverna.server.master.notification.atom.EventDAO;
+
+/**
+ * What the remote run really needs of its factory.
+ * 
+ * @author Donal Fellows
+ */
+public interface FactoryBean {
+	/**
+	 * @return Whether a run can actually be started at this time.
+	 */
+	boolean isAllowingRunsToStart();
+
+	/**
+	 * @return a handle to the master Atom event feed (<i>not</i> the per-run
+	 *         feed)
+	 */
+	EventDAO getMasterEventFeed();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
new file mode 100644
index 0000000..d3c5b8a
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PasswordIssuer.java
@@ -0,0 +1,57 @@
+package org.taverna.server.master.worker;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A simple password issuing bean.
+ * 
+ * @author Donal Fellows
+ */
+public class PasswordIssuer {
+	private static final char[] ALPHABET = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+			'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+			'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+			'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+			'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7',
+			'8', '9', '0', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+			',', '.', '<', '>', '/', '?', ':', ';', '-', '_', '+', '[', ']',
+			'{', '}', '`', '~' };
+	private Log log = LogFactory.getLog("Taverna.Server.Worker");
+	private SecureRandom r;
+	private int length;
+
+	public PasswordIssuer() {
+		r = new SecureRandom();
+		log.info("constructing passwords with " + r.getAlgorithm());
+		setLength(8);
+	}
+
+	public PasswordIssuer(String algorithm) throws NoSuchAlgorithmException {
+		r = SecureRandom.getInstance(algorithm);
+		log.info("constructing passwords with " + r.getAlgorithm());
+		setLength(8);
+	}
+
+	public void setLength(int length) {
+		this.length = length;
+		log.info("issued password will be " + this.length
+				+ " symbols chosen from " + ALPHABET.length);
+	}
+
+	/**
+	 * Issue a password.
+	 * 
+	 * @return The new password.
+	 */
+	public String issue() {
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0; i < length; i++)
+			sb.append(ALPHABET[r.nextInt(ALPHABET.length)]);
+		log.info("issued new password of length " + sb.length());
+		return sb.toString();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
new file mode 100644
index 0000000..f5613c7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyImpl.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import static org.taverna.server.master.identity.WorkflowInternalAuthProvider.PREFIX;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Required;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.taverna.server.master.common.Roles;
+import org.taverna.server.master.common.Workflow;
+import org.taverna.server.master.exceptions.NoCreateException;
+import org.taverna.server.master.exceptions.NoDestroyException;
+import org.taverna.server.master.exceptions.NoUpdateException;
+import org.taverna.server.master.interfaces.Policy;
+import org.taverna.server.master.interfaces.TavernaRun;
+import org.taverna.server.master.interfaces.TavernaSecurityContext;
+import org.taverna.server.master.utils.UsernamePrincipal;
+
+/**
+ * Basic policy implementation that allows any workflow to be instantiated by
+ * any user, but which does not permit users to access each others workflow
+ * runs. It also imposes a global limit on the number of workflow runs at once.
+ * 
+ * @author Donal Fellows
+ */
+class PolicyImpl implements Policy {
+	Log log = LogFactory.getLog("Taverna.Server.Worker.Policy");
+	private PolicyLimits limits;
+	private RunDBSupport runDB;
+
+	@Required
+	public void setLimits(PolicyLimits limits) {
+		this.limits = limits;
+	}
+
+	@Required
+	public void setRunDB(RunDBSupport runDB) {
+		this.runDB = runDB;
+	}
+
+	@Override
+	public int getMaxRuns() {
+		return limits.getMaxRuns();
+	}
+
+	@Override
+	public Integer getMaxRuns(UsernamePrincipal user) {
+		return null;
+	}
+
+	@Override
+	public int getOperatingLimit() {
+		return limits.getOperatingLimit();
+	}
+
+	@Override
+	public List<URI> listPermittedWorkflowURIs(UsernamePrincipal user) {
+		return limits.getPermittedWorkflowURIs();
+	}
+
+	private boolean isSelfAccess(String runId) {
+		Authentication auth = SecurityContextHolder.getContext()
+				.getAuthentication();
+		boolean self = false;
+		String id = null;
+		for (GrantedAuthority a : auth.getAuthorities()) {
+			String aa = a.getAuthority();
+			if (aa.equals(Roles.SELF)) {
+				self = true;
+				continue;
+			}
+			if (!aa.startsWith(PREFIX))
+				continue;
+			id = aa.substring(PREFIX.length());
+		}
+		return self && runId.equals(id);
+	}
+
+	@Override
+	public boolean permitAccess(UsernamePrincipal user, TavernaRun run) {
+		String username = user.getName();
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner().getName().equals(username)) {
+			if (log.isDebugEnabled())
+				log.debug("granted access by " + user.getName() + " to "
+						+ run.getId());
+			return true;
+		}
+		if (isSelfAccess(run.getId())) {
+			if (log.isDebugEnabled())
+				log.debug("access by workflow to itself: " + run.getId());
+			return true;
+		}
+		if (log.isDebugEnabled())
+			log.debug("considering access by " + user.getName() + " to "
+					+ run.getId());
+		return context.getPermittedReaders().contains(username);
+	}
+
+	@Override
+	public void permitCreate(UsernamePrincipal user, Workflow workflow)
+			throws NoCreateException {
+		if (user == null)
+			throw new NoCreateException(
+					"anonymous workflow creation not allowed");
+		if (runDB.countRuns() >= getMaxRuns())
+			throw new NoCreateException("server load exceeded; please wait");
+	}
+
+	@Override
+	public synchronized void permitDestroy(UsernamePrincipal user, TavernaRun run)
+			throws NoDestroyException {
+		if (user == null)
+			throw new NoDestroyException();
+		String username = user.getName();
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner() == null
+				|| context.getOwner().getName().equals(username))
+			return;
+		if (!context.getPermittedDestroyers().contains(username))
+			throw new NoDestroyException();
+	}
+
+	@Override
+	public void permitUpdate(UsernamePrincipal user, TavernaRun run)
+			throws NoUpdateException {
+		if (user == null)
+			throw new NoUpdateException(
+					"workflow run not owned by you and you're not granted access");
+		TavernaSecurityContext context = run.getSecurityContext();
+		if (context.getOwner().getName().equals(user.getName()))
+			return;
+		if (isSelfAccess(run.getId())) {
+			if (log.isDebugEnabled())
+				log.debug("update access by workflow to itself: " + run.getId());
+			return;
+		}
+		if (!context.getPermittedUpdaters().contains(user.getName()))
+			throw new NoUpdateException(
+					"workflow run not owned by you and you're not granted access");
+	}
+
+	@Override
+	public void setPermittedWorkflowURIs(UsernamePrincipal user,
+			List<URI> permitted) {
+		limits.setPermittedWorkflowURIs(permitted);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
new file mode 100644
index 0000000..8cbc7ea
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/worker/PolicyLimits.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.worker;
+
+import java.net.URI;
+import java.util.List;
+
+import org.taverna.server.master.common.Status;
+
+/**
+ * The worker policy delegates certain limits to the state model of the
+ * particular worker.
+ * 
+ * @author Donal Fellows
+ */
+public interface PolicyLimits {
+	/**
+	 * @return the maximum number of extant workflow runs in any state
+	 */
+	int getMaxRuns();
+
+	/**
+	 * @return the maximum number of workflow runs in the
+	 *         {@linkplain Status#Operating operating} state.
+	 */
+	int getOperatingLimit();
+
+	/**
+	 * @return the list of URIs to workflows that may be used to create workflow
+	 *         runs. If empty or <tt>null</tt>, no restriction is present.
+	 */
+	List<URI> getPermittedWorkflowURIs();
+
+	/**
+	 * @param permitted
+	 *            the list of URIs to workflows that may be used to create
+	 *            workflow runs.
+	 */
+	void setPermittedWorkflowURIs(List<URI> permitted);
+}


[11/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
new file mode 100644
index 0000000..e175bf8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/TavernaServerSOAP.java
@@ -0,0 +1,1553 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Roles.USER;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.security.RolesAllowed;
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.apache.cxf.annotations.WSDLDocumentation;
+import org.ogf.usage.JobUsageRecord;
+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.UnknownRunException;
+import org.taverna.server.master.rest.TavernaServerREST;
+import org.taverna.server.port_description.OutputDescription;
+
+/**
+ * The SOAP service interface to Taverna 3 Server.
+ * 
+ * @author Donal Fellows
+ * @see TavernaServerREST
+ */
+@RolesAllowed(USER)
+@WebService(name = "tavernaService", targetNamespace = SERVER_SOAP)
+@WSDLDocumentation("The SOAP service interface to Taverna " + Version.JAVA
+		+ " Server.")
+public interface TavernaServerSOAP {
+	/**
+	 * Make a run for a particular workflow.
+	 * 
+	 * @param workflow
+	 *            The workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow.")
+	RunReference submitWorkflow(
+			@WebParam(name = "workflow") @XmlElement(required = true) Workflow workflow)
+					throws NoUpdateException, NoCreateException;
+
+	/**
+	 * Make a run for a particular workflow.
+	 * 
+	 * @param workflow
+	 *            The workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow.")
+	RunReference submitWorkflowMTOM(
+			@WebParam(name = "workflow") @XmlElement(required = true) WrappedWorkflow workflow)
+			throws NoUpdateException;
+
+	/**
+	 * Make a run for a particular workflow, where that workflow will be
+	 * downloaded from elsewhere. The URI <i>must</i> be publicly readable.
+	 * 
+	 * @param workflowURI
+	 *            The URI to the workflow to instantiate.
+	 * @return Annotated handle for created run.
+	 * @throws NoUpdateException
+	 * @throws NoCreateException
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Make a run for a particular workflow where that "
+			+ "workflow is given by publicly readable URI.")
+	RunReference submitWorkflowByURI(
+			@WebParam(name = "workflowURI") @XmlElement(required = true) URI workflowURI)
+			throws NoCreateException, NoUpdateException;
+
+	/**
+	 * Get the list of existing runs owned by the user.
+	 * 
+	 * @return Annotated handle list.
+	 */
+	@WebResult(name = "Run")
+	@WSDLDocumentation("Get the list of existing runs owned by the user.")
+	RunReference[] listRuns();
+
+	/**
+	 * Get the upper limit on the number of runs that the user may create at
+	 * once.
+	 * 
+	 * @return The limit. <b>NB:</b> the number currently operating may be
+	 *         larger, but in that case no further runs can be made until some
+	 *         of the old ones are destroyed.
+	 */
+	@WebResult(name = "MaxSimultaneousRuns")
+	@WSDLDocumentation("Get the upper limit on the number of runs that the user may create at once.")
+	int getServerMaxRuns();
+
+	/**
+	 * Get the list of allowed workflows. If the list is empty, <i>any</i>
+	 * workflow may be used.
+	 * 
+	 * @return A list of workflow documents.
+	 */
+	@WebMethod(operationName = "getPermittedWorkflowURIs")
+	@WebResult(name = "PermittedWorkflowURI")
+	@WSDLDocumentation("Get the list of URIs to allowed workflows. If the list is empty, any workflow may be used including those not submitted via URI.")
+	URI[] getServerWorkflows();
+
+	/**
+	 * Get the list of allowed event listeners.
+	 * 
+	 * @return A list of listener names.
+	 */
+	@WebMethod(operationName = "getPermittedListenerTypes")
+	@WebResult(name = "PermittedListenerType")
+	@WSDLDocumentation("Get the list of allowed types of event listeners.")
+	String[] getServerListeners();
+
+	/**
+	 * Get the list of notification fabrics.
+	 * 
+	 * @return A list of listener names.
+	 */
+	@WebMethod(operationName = "getEnabledNotificationFabrics")
+	@WebResult(name = "EnabledNotifierFabric")
+	@WSDLDocumentation("Get the list of notification fabrics. Each is a URI scheme.")
+	String[] getServerNotifiers();
+
+	@WebMethod(operationName = "getCapabilities")
+	@WebResult(name = "Capabilities")
+	@WSDLDocumentation("Get the workflow execution capabilities of this "
+			+ "Taverna Server instance.")
+	List<Capability> getServerCapabilities();
+
+	/**
+	 * Destroy a run immediately. This might or might not actually relinquish
+	 * resources; that's up to the service implementation and deployment.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the lifetime of the
+	 *             run.
+	 */
+	@WSDLDocumentation("Destroy a run immediately.")
+	void destroyRun(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the workflow document used to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The workflow document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationWorkflow")
+	@WSDLDocumentation("Get the workflow document used to create the given run.")
+	Workflow getRunWorkflow(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the workflow document used to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The workflow document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationWorkflow")
+	@WSDLDocumentation("Get the workflow document used to create the given run.")
+	WrappedWorkflow getRunWorkflowMTOM(
+			@WebParam(name = "runName") String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get a description of the profiles supported by the workflow document used
+	 * to create the given run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return A description of the supported profiles.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Profiles")
+	@WSDLDocumentation("Get a description of the profiles supported by the workflow document used to create the given run.")
+	ProfileList getRunWorkflowProfiles(
+			@WebParam(name = "runName") String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the descriptive name of the workflow run. The descriptive name
+	 * carries no deep information.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The descriptive name of the run.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "DescriptiveName")
+	@WSDLDocumentation("Get the descriptive name of the workflow run. Carries no deep information.")
+	String getRunDescriptiveName(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the descriptive name of the workflow run. The descriptive name
+	 * carries no deep information.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param descriptiveName
+	 *            The new descriptive name to set. Note that the implementation
+	 *            is allowed to arbitrarily truncate this value.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not permitted to update this run.
+	 */
+	@WSDLDocumentation("Set the descriptive name of the workflow run. Carries no deep information.")
+	void setRunDescriptiveName(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "descriptiveName") @XmlElement(required = true) String descriptiveName)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the description of the inputs to the workflow run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The input description
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "RunInputDescription")
+	@WSDLDocumentation("Get the description of the inputs currently set up for the given workflow run.")
+	InputDescription getRunInputs(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get a description of what inputs the workflow run <i>expects</i> to
+	 * receive.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The description document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "RunInputDescriptor")
+	@WSDLDocumentation("Get a description of what inputs the given workflow run expects to receive.")
+	org.taverna.server.port_description.InputDescription getRunInputDescriptor(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Tells the run to use the given Baclava file for all inputs.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param fileName
+	 *            The name of the file to use. Must not start with a <tt>/</tt>
+	 *            or contain a <tt>..</tt> element.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state
+	 */
+	@WSDLDocumentation("Tells the given run to use the given already-uploaded Baclava file for all inputs.")
+	void setRunInputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "baclavaFileName") String fileName)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * Tells the run to use the given file for input on the given port. This
+	 * overrides any previously set file or value on the port and causes the
+	 * server to forget about using a Baclava file for all inputs.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to use the file for.
+	 * @param portFilename
+	 *            The file to use on the port. Must not start with a <tt>/</tt>
+	 *            or contain a <tt>..</tt> element.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the input port may not be changed to the contents of the
+	 *             given file.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given file for input on the given port.")
+	void setRunInputPortFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "portFileName") @XmlElement(required = true) String portFilename)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException,
+			BadPropertyValueException;
+
+	/**
+	 * Tells the run to use the given value for input on the given port. This
+	 * overrides any previously set file or value on the port and causes the
+	 * server to forget about using a Baclava file for all inputs. Note that
+	 * this is wholly unsuitable for use with binary data.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to use the file for.
+	 * @param portValue
+	 *            The literal value to use on the port.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the input port may not be changed to the given literal
+	 *             value.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given literal string value for input on the given port.")
+	void setRunInputPortValue(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "portValue") @XmlElement(required = true) String portValue)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException, BadPropertyValueException;
+
+	/**
+	 * Tells the given run to use the given list delimiter (a single-character
+	 * string value) for splitting the input on the given port. Note that
+	 * nullability of the delimiter is supported here.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param portName
+	 *            The port to set the list delimiter for.
+	 * @param delimiter
+	 *            The single-character value (in range U+00001..U+0007F) to use
+	 *            as the delimiter, or <tt>null</tt> for no delimiter at all.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state.
+	 * @throws BadPropertyValueException
+	 *             If the delimiter may not be changed to the given literal
+	 *             value.
+	 */
+	@WSDLDocumentation("Tells the given run to use the given list delimiter (a single-character string value) for splitting the input on the given port. Note that nullability of the delimiter is supported here.")
+	void setRunInputPortListDelimiter(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "portName") @XmlElement(required = true) String portName,
+			@WebParam(name = "delimiter") String delimiter)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException, BadPropertyValueException;
+
+	/**
+	 * Get the Baclava file where the output of the run will be written.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The filename, or <tt>null</tt> if the results will be written to
+	 *         a subdirectory <tt>out</tt> of the run's working directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "OutputBaclavaFile")
+	@WSDLDocumentation("Get the Baclava file where the output of the run will be written.")
+	String getRunOutputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the Baclava file where the output of the run will be written.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param outputFile
+	 *            The filename for the Baclava file, or <tt>null</tt> or the
+	 *            empty string to indicate that the results are to be written to
+	 *            the subdirectory <tt>out</tt> of the run's working directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws FilesystemAccessException
+	 *             If the filename is illegal (starts with a <tt>/</tt> or
+	 *             contains a <tt>..</tt> element.
+	 * @throws BadStateChangeException
+	 *             If the run is not in the {@link Status#Initialized
+	 *             Initialized} state
+	 */
+	@WSDLDocumentation("Set the Baclava file where the output of the run will be written.")
+	void setRunOutputBaclavaFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "baclavaFileName") String outputFile)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, BadStateChangeException;
+
+	/**
+	 * Return a description of the outputs of a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Description document (higher level than filesystem traverse).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws BadStateChangeException
+	 *             If the run is in the {@link Status#Initialized Initialized}
+	 *             state
+	 * @throws FilesystemAccessException
+	 *             If there is an exception when accessing the filesystem.
+	 * @throws NoDirectoryEntryException
+	 *             If things are odd in the filesystem.
+	 */
+	@WebResult(name = "OutputDescription")
+	@WSDLDocumentation("Return a description of the outputs of a run. Only known during/after the run.")
+	OutputDescription getRunOutputDescription(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, BadStateChangeException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the time when the run will be eligible to be automatically deleted.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return A date at which the expiry will be scheduled. The actual deletion
+	 *         will happen an arbitrary amount of time later (depending on
+	 *         system policy).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Expiry")
+	@WSDLDocumentation("Get the time when the run will be eligible to be automatically deleted.")
+	Date getRunExpiry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set when the run will be eligible to be automatically deleted.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param expiry
+	 *            A date at which the expiry will be scheduled. The actual
+	 *            deletion will happen an arbitrary amount of time later
+	 *            (depending on system policy).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the lifetime of the
+	 *             run.
+	 */
+	@WSDLDocumentation("Set when the run will be eligible to be automatically deleted.")
+	void setRunExpiry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "expiry") @XmlElement(required = true) Date expiry)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the time when the run was created.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was created (modulo some internal
+	 *         overhead).
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "CreationTime")
+	@WSDLDocumentation("Get the time when the run was created.")
+	Date getRunCreationTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the time when the run was started.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was started (modulo some internal
+	 *         overhead) or <tt>null</tt> to indicate that it has never started.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StartTime")
+	@WSDLDocumentation("Get the time when the run was started.")
+	Date getRunStartTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the time when the run was detected as having finished.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The moment when the run was believed stopped. Note that this may
+	 *         not be when the run <i>actually</i> finished; promptness of
+	 *         detection depends on many factors.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "FinishTime")
+	@WSDLDocumentation("Get the time when the run was detected as having finished.")
+	Date getRunFinishTime(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the current status of the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The status code.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Status")
+	@WSDLDocumentation("Get the current status of the given workflow run.")
+	Status getRunStatus(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Set the status of a run. This is used to start it executing, make it stop
+	 * executing, etc. Note that changing the status of a run can <i>never</i>
+	 * cause the run to be destroyed.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param status
+	 *            The status to change to. Changing to the current status will
+	 *            always have no effect.
+	 * @return An empty string if the state change was completed, or a
+	 *         description (never empty) of why the state change is ongoing.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws BadStateChangeException
+	 *             If the state change requested is impossible.
+	 */
+	@WebResult(name = "PartialityReason")
+	@WSDLDocumentation("Set the status of a given workflow run.")
+	String setRunStatus(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "status") @XmlElement(required = true) Status status)
+			throws UnknownRunException, NoUpdateException,
+			BadStateChangeException;
+
+	/**
+	 * Get the names of the event listeners attached to the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The listener names.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "ListenerName")
+	@WSDLDocumentation("Get the names of the event listeners attached to the run.")
+	String[] getRunListeners(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Adds an event listener to the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerType
+	 *            The type of event listener to add. Must be one of the names
+	 *            returned by the {@link #getServerListeners()} operation.
+	 * @param configuration
+	 *            The configuration document for the event listener; the
+	 *            interpretation of the configuration is up to the listener.
+	 * @return The actual name of the listener.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user isn't allowed to manipulate the run.
+	 * @throws NoListenerException
+	 *             If the listener construction fails (<i>e.g.</i>, due to an
+	 *             unsupported <b>listenerType</b> or a problem with the
+	 *             <b>configuration</b>).
+	 */
+	@WebResult(name = "ListenerName")
+	@WSDLDocumentation("Adds an event listener to the run.")
+	String addRunListener(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerType") @XmlElement(required = true) String listenerType,
+			@WebParam(name = "configuration") @XmlElement(required = true) String configuration)
+			throws UnknownRunException, NoUpdateException, NoListenerException;
+
+	/**
+	 * Returns the standard output of the workflow run. Unstarted runs return
+	 * the empty string.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/stdout).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine printed on its stdout.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StandardOutput")
+	@WSDLDocumentation("Returns the stdout from the run engine.")
+	String getRunStdout(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the standard error of the workflow run. Unstarted runs return the
+	 * empty string.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/stderr).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine printed on its stderr.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "StandardError")
+	@WSDLDocumentation("Returns the stderr from the run engine.")
+	String getRunStderr(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the usage record for the workflow run. Unfinished runs return
+	 * <tt>null</tt>.
+	 * <p>
+	 * The equivalent thing can also be fetched from the relevant listener
+	 * property (i.e., io/usage).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The usage record, or <tt>null</tt>.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "ResourceUsage")
+	@WSDLDocumentation("Returns the resource usage from the run engine.")
+	JobUsageRecord getRunUsageRecord(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the log of the workflow run. Unstarted runs return the empty
+	 * string.
+	 * <p>
+	 * This can also be fetched from the appropriate file (i.e.,
+	 * <tt>logs/detail.log</tt>).
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whatever the run engine wrote to its log.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Log")
+	@WSDLDocumentation("Returns the detailed log from the run engine.")
+	String getRunLog(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Returns the run bundle of a run. The run must be <i>finished</i> for this
+	 * to be guaranteed to be present, and must <i>not</i> have had its output
+	 * generated as Baclava.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The contents of the run bundle.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If there was a problem reading the bundle.
+	 * @throws NoDirectoryEntryException
+	 *             If the bundle doesn't exist currently.
+	 */
+	@WebResult(name = "RunBundle")
+	@WSDLDocumentation("Gets the run bundle of a finished run. MTOM support recommended!")
+	FileContents getRunBundle(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Gets whether to generate provenance (in a run bundle) for a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return Whether provenance will be generated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "GenerateProvenance")
+	@WSDLDocumentation("Gets whether a run generates provenance.")
+	boolean getRunGenerateProvenance(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Sets whether to generate provenance (in a run bundle) for a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param generateProvenance
+	 *            Whether to generate provenance.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to manipulate the run.
+	 */
+	@WSDLDocumentation("Sets whether a run generates provenance. "
+			+ "Only usefully settable before the run is started.")
+	void setRunGenerateProvenance(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "generateProvenance") @XmlElement(required = true) boolean generateProvenance)
+			throws UnknownRunException, NoUpdateException;
+
+	/**
+	 * Get the owner of the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The status code.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 */
+	@WebResult(name = "Owner")
+	@WSDLDocumentation("Get the owner of the given workflow run.")
+	String getRunOwner(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException;
+
+	/**
+	 * Get the list of permissions associated with a workflow run.
+	 * 
+	 * @param runName
+	 *            The name of the run whose permissions are to be obtained.
+	 * @return A description of the non-<tt>none</tt> permissions.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the current
+	 *             user is not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If asked to provide this information about a run that the
+	 *             current user may see but where they are not the owner of it.
+	 */
+	@WebResult(name = "PermissionList")
+	@WSDLDocumentation("Get the list of permissions associated with a given workflow run.")
+	PermissionList listRunPermissions(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set the permission for a user to access and update a particular workflow
+	 * run.
+	 * 
+	 * @param runName
+	 *            The name of the run whose permissions are to be updated.
+	 * @param userName
+	 *            The name of the user about whom this call is talking.
+	 * @param permission
+	 *            The permission level to set.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the current
+	 *             user is not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If asked to provide this information about a run that the
+	 *             current user may see but where they are not the owner of it.
+	 */
+	@WSDLDocumentation("Set the permission for a user to access and update a given workflow run.")
+	void setRunPermission(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "userName") @XmlElement(required = true) String userName,
+			@WebParam(name = "permission") @XmlElement(required = true) Permission permission)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Get the credentials associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The collection of credentials.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may see the credentials.
+	 */
+	@WebResult(name = "Credentials")
+	@WSDLDocumentation("Get the credentials (passwords, private keys) associated with the given workflow run. Only the owner may do this.")
+	Credential[] getRunCredentials(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set a credential associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param credentialID
+	 *            The handle of the credential to set. If empty, a new
+	 *            credential will be created.
+	 * @param credential
+	 *            The credential to set.
+	 * @return The handle of the credential that was created or updated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the credentials.
+	 * @throws InvalidCredentialException
+	 *             If the <b>credential</b> fails its checks.
+	 * @throws NoCredentialException
+	 *             If the <b>credentialID</b> is not empty but does not
+	 *             correspond to an existing credential.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WebResult(name = "credentialID")
+	@WSDLDocumentation("Set a credential (password, private key, etc.) associated with the given run. Only the owner may do this.")
+	String setRunCredential(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID,
+			@WebParam(name = "credential") @XmlElement(required = true) Credential credential)
+			throws UnknownRunException, NotOwnerException,
+			InvalidCredentialException, NoCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Delete a credential associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param credentialID
+	 *            The handle of the credential to delete. If empty, a new
+	 *            credential will be created.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the credentials.
+	 * @throws NoCredentialException
+	 *             If the given credentialID does not exist.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WSDLDocumentation("Delete a credential associated with the given run. Only the owner may do this.")
+	void deleteRunCredential(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "credentialID") @XmlElement(required = true) String credentialID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException;
+
+	/**
+	 * Get the certificate collections associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @return The collection of credentials.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may see the credentials.
+	 */
+	@WebResult(name = "CertificateCollections")
+	@WSDLDocumentation("Get the trusted (server or CA) certificates associated with the run. Only the owner may do this.")
+	Trust[] getRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName)
+			throws UnknownRunException, NotOwnerException;
+
+	/**
+	 * Set a certificate collection associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param certificateID
+	 *            The handle of the certificate collection to set. If empty, a
+	 *            new certificate collection will be created.
+	 * @param certificate
+	 *            The certificate collection to set.
+	 * @return The handle of the certificate set that was created or updated.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the certificates.
+	 * @throws InvalidCredentialException
+	 *             If the <b>certificate</b> fails its checks.
+	 * @throws NoCredentialException
+	 *             If the <b>credentialID</b> is not empty but does not
+	 *             correspond to an existing certificate collection.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WebResult(name = "certificateID")
+	@WSDLDocumentation("Set a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
+	String setRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "certificateID") String certificateID,
+			@WebParam(name = "certificate") @XmlElement(required = true) Trust certificate)
+			throws UnknownRunException, NotOwnerException,
+			InvalidCredentialException, NoCredentialException,
+			BadStateChangeException;
+
+	/**
+	 * Delete a certificate collection associated with the run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param certificateID
+	 *            The handle of the credential to delete.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NotOwnerException
+	 *             If the user is permitted to see the run, but isn't the owner;
+	 *             only the owner may manipulate the certificates.
+	 * @throws NoCredentialException
+	 *             If the given certificateID does not exist.
+	 * @throws BadStateChangeException
+	 *             If an attempt to manipulate the credentials is done after the
+	 *             workflow has started running.
+	 */
+	@WSDLDocumentation("Delete a trusted (server or CA) certificate associated with the run. Only the owner may do this.")
+	void deleteRunCertificates(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "certificateID") @XmlElement(required = true) String certificateID)
+			throws UnknownRunException, NotOwnerException,
+			NoCredentialException, BadStateChangeException;
+
+	/**
+	 * Get the contents of any directory at/under the run's working directory.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return A list of entries. They are assumed to be all directories or
+	 *         files.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "DirectoryEntry")
+	@WSDLDocumentation("Get the contents of any directory at/under the run's working directory.")
+	DirEntry[] getRunDirectoryContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of any directory (and its subdirectories) at/under the
+	 * run's working directory, returning it as a compressed ZIP file. Runs do
+	 * not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return A serialized ZIP file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "ZipFile")
+	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file.")
+	byte[] getRunDirectoryAsZip(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of any directory (and its subdirectories) at/under the
+	 * run's working directory, returning it as a compressed ZIP file that is
+	 * streamed via MTOM. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param directory
+	 *            The name of the directory to fetch; the main working directory
+	 *            is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return An MTOM-streamable ZIP file reference.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a file).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the directory can't be looked up.
+	 */
+	@WebResult(name = "ZipStream")
+	@WSDLDocumentation("Get the contents of any directory (and its subdirectories) at/under the run's working directory, returning it as a compressed ZIP file that is streamed by MTOM.")
+	ZippedDirectory getRunDirectoryAsZipMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directory") @XmlElement(required = true) DirEntry directory)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Make a new empty directory beneath an existing one, which must be the
+	 * run's working directory or a directory beneath it. Runs do not share
+	 * working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param parent
+	 *            The parent directory that will have the new directory added
+	 *            beneath it.
+	 * @param name
+	 *            The name of the directory to create. Must not be the same as
+	 *            any other file or directory in the <i>parent</i> directory.
+	 *            The name <i>must not</i> consist of <tt>..</tt> or have a
+	 *            <tt>/</tt> in it.
+	 * @return A reference to the created directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., making something with
+	 *             the same name as something that already exists).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 */
+	@WebResult(name = "CreatedDirectory")
+	@WSDLDocumentation("Make a new empty directory beneath an existing one, all relative to the given run's main working directory.")
+	DirEntry makeRunDirectory(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
+			@WebParam(name = "directoryName") @XmlElement(required = true) String name)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Make a new empty file in an existing directory, which may be the run's
+	 * working directory or any directory beneath it. Runs do not share working
+	 * directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param parent
+	 *            The parent directory that will have the new file added to it.
+	 * @param name
+	 *            The name of the file to create. Must not be the same as any
+	 *            other file or directory in the <i>parent</i> directory. The
+	 *            name <i>must not</i> consist of <tt>..</tt> or have a
+	 *            <tt>/</tt> in it.
+	 * @return A reference to the created file. The file will be empty.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., making something with
+	 *             the same name as something that already exists).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the containing directory can't be looked up.
+	 */
+	@WebResult(name = "CreatedFile")
+	@WSDLDocumentation("Make a new empty file in an existing directory, which may be the run's working directory or any directory beneath it.")
+	DirEntry makeRunFile(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "parentDirectory") @XmlElement(required = true) DirEntry parent,
+			@WebParam(name = "fileNameTail") @XmlElement(required = true) String name)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Destroy an entry (file or directory) in or beneath a run's working
+	 * directory. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param dirEntry
+	 *            Reference to an existing item in a directory that will be
+	 *            destroyed. May be a reference to either a file or a directory.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., deleting something
+	 *             which doesn't exist or attempting to delete the main working
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the name of the file or directory can't be looked up.
+	 */
+	@WSDLDocumentation("Destroy an entry (file or directory) in or beneath a run's working directory.")
+	void destroyRunDirectoryEntry(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "directoryEntry") @XmlElement(required = true) DirEntry dirEntry)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to fetch; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The literal byte contents of the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContents")
+	@WSDLDocumentation("Get the contents of a file under the run's working directory.")
+	byte[] getRunFileContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the contents of a file under the run's working directory via MTOM.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to fetch; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The contents, described for transfer via MTOM.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContentsMTOM")
+	@WSDLDocumentation("Get the contents of a file via MTOM.")
+	FileContents getRunFileContentsMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to update; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @param newContents
+	 *            The literal bytes to set the file contents to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
+	void setRunFileContents(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file,
+			@WebParam(name = "contents") @XmlElement(required = true) byte[] newContents)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory. Runs do not
+	 * share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param newContents
+	 *            The description of what file to set, and what to the file
+	 *            contents should be set to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory.")
+	void setRunFileContentsMTOM(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "contents") @XmlElement(required = true) FileContents newContents)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Set the contents of a file under the run's working directory to the
+	 * contents of a publicly readable URI. Runs do not share working
+	 * directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to update; the main working directory is
+	 *            <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @param reference
+	 *            The publicly readable URI whose contents are to become the
+	 *            literal bytes of the file's contents.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., writing the contents of
+	 *             a directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WSDLDocumentation("Set the contents of a file under the run's working directory from the contents of a publicly readable URI.")
+	void setRunFileContentsFromURI(@WebParam(name = "runName") String runName,
+			@WebParam(name = "fileName") DirEntryReference file,
+			@WebParam(name = "contents") URI reference)
+			throws UnknownRunException, NoUpdateException,
+			FilesystemAccessException, NoDirectoryEntryException;
+
+	/**
+	 * Get the length of any file (in bytes) at/under the run's working
+	 * directory. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the length of; the main working
+	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The number of bytes in the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the length of a
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileLength")
+	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
+	long getRunFileLength(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the time that the file or directory (at/under the run's working
+	 * directory) was last modified. Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the modification date of; the main
+	 *            working directory is <tt>/</tt> and <tt>..</tt> is always
+	 *            disallowed.
+	 * @return The modification date of the file or directory, as understood by
+	 *         the underlying operating system.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated.
+	 * @throws NoDirectoryEntryException
+	 *             If the file or directory doesn't exist.
+	 */
+	@WebResult(name = "FileModified")
+	@WSDLDocumentation("Get the length of any file (in bytes) at/under the run's working directory.")
+	Date getRunFileModified(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the content type of any file at/under the run's working directory.
+	 * Runs do not share working directories.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param file
+	 *            The name of the file to get the length of; the main working
+	 *            directory is <tt>/</tt> and <tt>..</tt> is always disallowed.
+	 * @return The content type of the file.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws FilesystemAccessException
+	 *             If some assumption is violated (e.g., reading the length of a
+	 *             directory).
+	 * @throws NoDirectoryEntryException
+	 *             If the file doesn't exist.
+	 */
+	@WebResult(name = "FileContentType")
+	@WSDLDocumentation("Get the content type of any file at/under the run's working directory.")
+	String getRunFileType(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "fileName") @XmlElement(required = true) DirEntry file)
+			throws UnknownRunException, FilesystemAccessException,
+			NoDirectoryEntryException;
+
+	/**
+	 * Get the configuration document for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @return The configuration document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists.
+	 */
+	@WebResult(name = "ListenerConfiguration")
+	@WSDLDocumentation("Get the configuration document for an event listener attached to a run.")
+	String getRunListenerConfiguration(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Get the list of properties supported by an event listener attached to a
+	 * run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @return The list of property names.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists.
+	 */
+	@WebResult(name = "ListenerPropertyName")
+	@WSDLDocumentation("Get the list of properties supported by an event listener attached to a run.")
+	String[] getRunListenerProperties(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Get the value of a property for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @param propertyName
+	 *            The name of the property to read.
+	 * @return The configuration document.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists or if the listener has no such
+	 *             property.
+	 */
+	@WebResult(name = "ListenerPropertyValue")
+	@WSDLDocumentation("Get the value of a property for an event listener attached to a run.")
+	String getRunListenerProperty(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
+			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName)
+			throws UnknownRunException, NoListenerException;
+
+	/**
+	 * Set the value of a property for an event listener attached to a run.
+	 * 
+	 * @param runName
+	 *            The handle of the run.
+	 * @param listenerName
+	 *            The name of the listener attached.
+	 * @param propertyName
+	 *            The name of the property to write.
+	 * @param value
+	 *            The value to set the property to.
+	 * @throws UnknownRunException
+	 *             If the server doesn't know about the run or if the user is
+	 *             not permitted to see it.
+	 * @throws NoListenerException
+	 *             If no such listener exists, the listener has no such
+	 *             property, or the value is considered "unacceptable" in some
+	 *             way.
+	 * @throws NoUpdateException
+	 *             If the user is not allowed to make modifications to the run.
+	 */
+	@WSDLDocumentation("Set the value of a property for an event listener attached to a run.")
+	void setRunListenerProperty(
+			@WebParam(name = "runName") @XmlElement(required = true) String runName,
+			@WebParam(name = "listenerName") @XmlElement(required = true) String listenerName,
+			@WebParam(name = "propertyName") @XmlElement(required = true) String propertyName,
+			@WebParam(name = "propertyValue") @XmlElement(required = true) String value)
+			throws UnknownRunException, NoUpdateException, NoListenerException;
+
+	/**
+	 * Gets the status of the server. Follows the HELIO Monitoring Service
+	 * protocol.
+	 * 
+	 * @return A status string.
+	 */
+	@WSDLDocumentation("A simple way to get the status of the overall server.")
+	@WebResult(name = "ServerStatus")
+	String getServerStatus();
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
new file mode 100644
index 0000000..cd06115
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/WrappedWorkflow.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE.txt" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import static javax.xml.bind.annotation.XmlAccessType.NONE;
+import static org.apache.commons.io.IOUtils.closeQuietly;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.Workflow;
+
+import uk.org.taverna.scufl2.api.io.ReaderException;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+import uk.org.taverna.scufl2.api.io.WriterException;
+
+/**
+ * An MTOM-capable description of how to transfer the contents of a file.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "WorkflowReference")
+@XmlAccessorType(NONE)
+public class WrappedWorkflow {
+	@XmlMimeType("application/octet-stream")
+	// JAXB bug: must be this
+	public DataHandler workflowData;
+	Workflow workflow;
+
+	/**
+	 * Initialize the contents of this descriptor from the given file and
+	 * content type.
+	 * 
+	 * @param workflow
+	 *            The workflow that is to be reported.
+	 */
+	public void setWorkflow(Workflow workflow) {
+		workflowData = new DataHandler(new WorkflowSource(workflow));
+	}
+
+	@XmlTransient
+	public Workflow getWorkflow() throws IOException {
+		if (workflow != null)
+			return workflow;
+		try {
+			return new Workflow(new WorkflowBundleIO().readBundle(
+					workflowData.getInputStream(), null));
+		} catch (ReaderException e) {
+			throw new IOException("problem converting to scufl2 bundle", e);
+		}
+	}
+}
+
+/**
+ * A data source that knows how to deliver a workflow.
+ * 
+ * @author Donal Fellows
+ */
+class WorkflowSource implements DataSource {
+	WorkflowSource(Workflow workflow) {
+		this.wf = workflow;
+		this.io = new WorkflowBundleIO();
+	}
+
+	Workflow wf;
+	final WorkflowBundleIO io;
+
+	@Override
+	public String getContentType() {
+		return wf.getPreferredContentType().getContentType();
+	}
+
+	@Override
+	public String getName() {
+		switch (wf.getPreferredContentType()) {
+		case SCUFL2:
+			return "workflow.scufl2";
+		case T2FLOW:
+			return "workflow.t2flow";
+		default:
+			return "workflow";
+		}
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		PipedInputStream is = new PipedInputStream();
+		final OutputStream os = new PipedOutputStream(is);
+		new Worker() {
+			@Override
+			public void doWork() throws WriterException, IOException {
+				io.writeBundle(wf.getScufl2Workflow(), os, wf
+						.getPreferredContentType().getContentType());
+			}
+
+			@Override
+			public void doneWork() {
+				closeQuietly(os);
+			}
+		};
+		return is;
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		final PipedInputStream is = new PipedInputStream();
+		OutputStream os = new PipedOutputStream(is);
+		new Worker() {
+			@Override
+			public void doWork() throws IOException, ReaderException {
+				wf = new Workflow(io.readBundle(is, null));
+			}
+
+			@Override
+			public void doneWork() {
+				closeQuietly(is);
+			}
+		};
+		return os;
+	}
+
+	static abstract class Worker extends Thread {
+		public Worker() {
+			setDaemon(true);
+			start();
+		}
+
+		public abstract void doWork() throws Exception;
+
+		public abstract void doneWork();
+
+		@Override
+		public void run() {
+			try {
+				doWork();
+			} catch (Exception e) {
+				// do nothing.
+			} finally {
+				doneWork();
+			}
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
new file mode 100644
index 0000000..90fe51b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/ZippedDirectory.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.activation.UnsupportedDataTypeException;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.Directory;
+
+/**
+ * An MTOM-capable description of how to transfer the zipped contents of a
+ * directory.
+ * 
+ * @author Donal Fellows
+ * @see Directory#getContentsAsZip()
+ */
+@XmlType(name = "ZippedDirectory")
+public class ZippedDirectory {
+	@XmlElement
+	public String name;
+	@XmlMimeType("application/octet-stream")
+	// JAXB bug: must be this
+	public DataHandler fileData;
+
+	public ZippedDirectory() {
+	}
+
+	/**
+	 * Initialise the contents of this descriptor from the given directory.
+	 * 
+	 * @param dir
+	 *            The directory that is to be reported.
+	 */
+	public ZippedDirectory(Directory dir) {
+		name = dir.getFullName();
+		fileData = new DataHandler(new ZipSource(dir));
+	}
+}
+
+/**
+ * A data source that knows how to communicate with the Taverna Server back-end.
+ * 
+ * @author Donal Fellows
+ */
+class ZipSource implements DataSource {
+	ZipSource(Directory d) {
+		this.d = d;
+	}
+
+	private final Directory d;
+
+	@Override
+	public String getContentType() {
+		return APPLICATION_ZIP_TYPE.toString();
+	}
+
+	@Override
+	public String getName() {
+		return d.getName();
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		try {
+			return d.getContentsAsZip();
+		} catch (FilesystemAccessException e) {
+			throw new IOException(e);
+		}
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		throw new UnsupportedDataTypeException();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
new file mode 100644
index 0000000..51d9b69
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the SOAP interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_SOAP, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.soap;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
new file mode 100644
index 0000000..487dbd0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecord.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.usage;
+
+import java.util.Date;
+
+import javax.jdo.annotations.Column;
+import javax.jdo.annotations.Index;
+import javax.jdo.annotations.PersistenceCapable;
+import javax.jdo.annotations.Persistent;
+import javax.jdo.annotations.PrimaryKey;
+import javax.jdo.annotations.Queries;
+import javax.jdo.annotations.Query;
+import javax.xml.bind.JAXBException;
+
+import org.ogf.usage.JobUsageRecord;
+
+/**
+ * A usage record as recorded in the database.
+ * 
+ * @author Donal Fellows
+ */
+@PersistenceCapable(table = "USAGE_RECORD_LOG", schema = "UR", cacheable = "true")
+@Queries({ @Query(name = "allByDate", value = "SELECT USAGE_RECORD FROM UR.USAGE_RECORD_LOG ORDER BY CREATE_DATE", resultClass = String.class, unmodifiable = "true", unique = "false", language = "SQL") })
+public class UsageRecord {
+	/**
+	 * Create an empty usage record database entry.
+	 */
+	public UsageRecord() {
+	}
+
+	/**
+	 * Create a usage record database entry that is populated from the given UR.
+	 * 
+	 * @param usageRecord
+	 *            The originating usage record.
+	 * @throws JAXBException
+	 *             If deserialization of the record fails.
+	 */
+	public UsageRecord(String usageRecord) throws JAXBException {
+		JobUsageRecord jur = JobUsageRecord.unmarshal(usageRecord);
+		setUsageRecord(usageRecord);
+		setCreateDate(jur.getRecordIdentity().getCreateTime()
+				.toGregorianCalendar().getTime());
+		setId(jur.getRecordIdentity().getRecordId());
+		setUserid(jur.getUserIdentity().get(0).getLocalUserId());
+	}
+
+	/**
+	 * Create a usage record database entry that is populated from the given UR.
+	 * 
+	 * @param usageRecord
+	 *            The originating usage record.
+	 * @throws JAXBException
+	 *             If serialization of the record fails.
+	 */
+	public UsageRecord(JobUsageRecord usageRecord) throws JAXBException {
+		setUsageRecord(usageRecord.marshal());
+		setCreateDate(usageRecord.getRecordIdentity().getCreateTime()
+				.toGregorianCalendar().getTime());
+		setId(usageRecord.getRecordIdentity().getRecordId());
+		setUserid(usageRecord.getUserIdentity().get(0).getLocalUserId());
+	}
+
+	@PrimaryKey
+	@Column(name = "ID", length = 40)
+	private String id;
+
+	@Persistent
+	@Index(name = "USERID_IDX")
+	@Column(name = "USERID", length = 24)
+	private String userid;
+
+	@Persistent
+	@Index(name = "CREATE_IDX")
+	@Column(name = "CREATE_DATE")
+	private Date createDate;
+
+	@Persistent
+	@Column(name = "USAGE_RECORD", length = 32000)
+	// TODO Consider moving to BLOB (CLOB?) type
+	private String usageRecord;
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getUserid() {
+		return userid;
+	}
+
+	public void setUserid(String userid) {
+		this.userid = userid;
+	}
+
+	public Date getCreateDate() {
+		return createDate;
+	}
+
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+
+	public String getUsageRecord() {
+		return usageRecord;
+	}
+
+	public void setUsageRecord(String usageRecord) {
+		this.usageRecord = usageRecord;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
new file mode 100644
index 0000000..12de304
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/UsageRecordRecorder.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.usage;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.logging.Log;
+import org.ogf.usage.JobUsageRecord;
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.api.ManagementModel;
+import org.taverna.server.master.utils.Contextualizer;
+import org.taverna.server.master.utils.JDOSupport;
+
+/**
+ * A simple state-aware writer of usage records. It just appends them, one by
+ * one, to the file whose name is stored in the state.
+ * 
+ * @author Donal Fellows
+ */
+public class UsageRecordRecorder extends JDOSupport<UsageRecord> {
+	private Log log = getLog("Taverna.Server.Webapp");
+	public UsageRecordRecorder() {
+		super(UsageRecord.class);
+	}
+
+	private String logFile = null;
+	private boolean disableDB = false;
+	private ManagementModel state;
+	private Contextualizer contextualizer;
+	private String logDestination;
+	private PrintWriter writer;
+	private Object lock = new Object();
+	private UsageRecordRecorder self;
+
+	/**
+	 * @param state
+	 *            the state to set
+	 */
+	@Required
+	public void setState(ManagementModel state) {
+		this.state = state;
+	}
+
+	@Required
+	public void setSelf(UsageRecordRecorder self) {
+		this.self = self;
+	}
+
+	public void setLogFile(String logFile) {
+		this.logFile = (logFile == null || logFile.equals("none")) ? null : logFile;
+	}
+
+	public void setDisableDB(String disable) {
+		disableDB = "yes".equalsIgnoreCase(disable);
+	}
+
+	/**
+	 * @param contextualizer
+	 *            the system's contextualizer, used to allow making the UR dump
+	 *            file be placed relative to the webapp.
+	 */
+	@Required
+	public void setContextualizer(Contextualizer contextualizer) {
+		this.contextualizer = contextualizer;
+	}
+
+	/**
+	 * Accept a usage record for recording.
+	 * 
+	 * @param usageRecord
+	 *            The serialized usage record to record.
+	 */
+	public void storeUsageRecord(String usageRecord) {
+		String logfile = state.getUsageRecordLogFile();
+		if (logfile == null)
+			logfile = this.logFile;
+		if (logfile != null) {
+			logfile = contextualizer.contextualize(logfile);
+			synchronized (lock) {
+				if (!logfile.equals(logDestination)) {
+					if (writer != null) {
+						writer.close();
+						writer = null;
+					}
+					try {
+						writer = new PrintWriter(new FileWriter(logfile));
+						logDestination = logfile;
+					} catch (IOException e) {
+						log.warn("failed to open usage record log file", e);
+					}
+				}
+				if (writer != null) {
+					writer.println(usageRecord);
+					writer.flush();
+				}
+			}
+		}
+
+		if (!disableDB)
+			saveURtoDB(usageRecord);
+	}
+
+	/**
+	 * How to save a usage record to the database.
+	 * 
+	 * @param usageRecord
+	 *            The serialized usage record to save.
+	 */
+	protected void saveURtoDB(String usageRecord) {
+		UsageRecord ur;
+		try {
+			ur = new UsageRecord(usageRecord);
+		} catch (JAXBException e) {
+			log.warn("failed to deserialize usage record", e);
+			return;
+		}
+
+		try {
+			self.saveURtoDB(ur);
+		} catch (RuntimeException e) {
+			log.warn("failed to save UR to database", e);
+		}
+	}
+
+	@WithinSingleTransaction
+	public void saveURtoDB(UsageRecord ur) {
+		persist(ur);
+	}
+
+	@WithinSingleTransaction
+	public List<JobUsageRecord> getUsageRecords() {
+		@SuppressWarnings("unchecked")
+		Collection<String> urs = (Collection<String>) namedQuery("allByDate")
+				.execute();
+		List<JobUsageRecord> result = new ArrayList<>();
+		for (String ur : urs)
+			try {
+				result.add(JobUsageRecord.unmarshal(ur));
+			} catch (JAXBException e) {
+				log.warn("failed to unmarshal UR", e);
+			}
+		return result;
+	}
+
+	@PreDestroy
+	public void close() {
+		if (writer != null)
+			writer.close();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
new file mode 100644
index 0000000..13e14cd
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/usage/package-info.java
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * Resource usage recording mechanism.
+ */
+package org.taverna.server.master.usage;


[12/49] incubator-taverna-server git commit: taverna-* module names

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
new file mode 100644
index 0000000..20d9f56
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/EntryHandler.java
@@ -0,0 +1,131 @@
+package org.taverna.server.master.rest.handler;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonMap;
+import static javax.ws.rs.core.Response.notAcceptable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Variant;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+
+@Provider
+@Produces({ "application/atom+xml", "application/atom+xml;type=entry" })
+@Consumes({ "application/atom+xml", "application/atom+xml;type=entry" })
+public class EntryHandler implements MessageBodyWriter<Entry>,
+		MessageBodyReader<Entry> {
+	private static final String ENC = "UTF-8";
+	private static final MediaType ENTRY = new MediaType("application",
+			"atom+xml", singletonMap("type", "entry"));
+	private static final Variant VARIANT = new Variant(ENTRY, (String) null,
+			ENC);
+	private static final Charset UTF8 = Charset.forName(ENC);
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		parser = abdera.getParser();
+		writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	private Parser parser;
+	private Writer writer;
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Entry.class.isAssignableFrom(type))
+			return false;
+		if (!ENTRY.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
+					"type"));
+		return true;
+	}
+
+	@Override
+	public Entry readFrom(Class<Entry> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		Charset cs = UTF8;
+		try {
+			String charset = mediaType.getParameters().get("charset");
+			if (charset != null)
+				cs = Charset.forName(charset);
+		} catch (IllegalCharsetNameException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("bad charset name").build());
+		} catch (UnsupportedCharsetException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("unsupportd charset name").build());
+		}
+		try {
+			Document<Entry> doc = parser.parse(new InputStreamReader(
+					entityStream, cs));
+			if (!Entry.class.isAssignableFrom(doc.getRoot().getClass())) {
+				throw new WebApplicationException(
+						notAcceptable(asList(VARIANT)).entity(
+								"not really a feed entry").build());
+			}
+			return doc.getRoot();
+		} catch (ClassCastException e) {
+			throw new WebApplicationException(notAcceptable(asList(VARIANT))
+					.entity("not really a feed entry").build());
+
+		}
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Entry.class.isAssignableFrom(type))
+			return false;
+		if (!ENTRY.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "entry".equalsIgnoreCase(mediaType.getParameters().get(
+					"type"));
+		return true;
+	}
+
+	@Override
+	public long getSize(Entry t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Entry t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		httpHeaders.putSingle("Content-Type", ENTRY.toString() + ";charset="
+				+ ENC);
+		writer.writeTo(t, new OutputStreamWriter(entityStream, UTF8));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
new file mode 100644
index 0000000..7c17f5c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FeedHandler.java
@@ -0,0 +1,66 @@
+package org.taverna.server.master.rest.handler;
+
+import static java.util.Collections.singletonMap;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.writer.Writer;
+import org.springframework.beans.factory.annotation.Required;
+
+@Provider
+@Produces({ "application/atom+xml", "application/atom+xml;type=feed" })
+public class FeedHandler implements MessageBodyWriter<Feed> {
+	private static final MediaType FEED = new MediaType("application",
+			"atom+xml", singletonMap("type", "feed"));
+	private static final String ENC = "UTF-8";
+
+	@Required
+	public void setAbdera(Abdera abdera) {
+		writer = abdera.getWriterFactory().getWriter("prettyxml");
+	}
+
+	private Writer writer;
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (!Feed.class.isAssignableFrom(type))
+			return false;
+		if (!FEED.isCompatible(mediaType))
+			return false;
+		if (mediaType.getParameters().containsKey("type"))
+			return "feed".equalsIgnoreCase(mediaType.getParameters()
+					.get("type"));
+		return true;
+	}
+
+	@Override
+	public long getSize(Feed t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Feed t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		httpHeaders.putSingle("Content-Type", FEED.toString() + ";charset="
+				+ ENC);
+		writer.writeTo(t, new OutputStreamWriter(entityStream, ENC));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
new file mode 100644
index 0000000..ab18d73
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileConcatenationHandler.java
@@ -0,0 +1,61 @@
+package org.taverna.server.master.rest.handler;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.springframework.beans.factory.annotation.Required;
+import org.taverna.server.master.FileConcatenation;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+public class FileConcatenationHandler implements
+		MessageBodyWriter<FileConcatenation> {
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	@Required
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(FileConcatenation.class);
+	}
+
+	@Override
+	public long getSize(FileConcatenation fc, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return fc.size();
+	}
+
+	@Override
+	public void writeTo(FileConcatenation fc, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException {
+		for (File f : fc)
+			try {
+				byte[] buffer;
+				for (int off = 0; true ; off += buffer.length) {
+					buffer = f.getContents(off, maxChunkSize);
+					if (buffer == null || buffer.length == 0)
+						break;
+					entityStream.write(buffer);
+				}
+			} catch (FilesystemAccessException e) {
+				// Ignore/skip to next file
+			}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
new file mode 100644
index 0000000..0aeb816
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileMessageHandler.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * How to write out a File object with JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class FileMessageHandler implements MessageBodyWriter<File> {
+	private Log log = getLog("Taverna.Server.Webapp");
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return File.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public long getSize(File t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		try {
+			return t.getSize(); // Is it really raw bytes?
+		} catch (FilesystemAccessException e) {
+			log.info("failed to get file length", e);
+			return -1;
+		}
+	}
+
+	@Override
+	public void writeTo(File t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			int off = 0;
+			while (true) {
+				byte[] buffer = t.getContents(off, maxChunkSize);
+				if (buffer == null || buffer.length == 0)
+					break;
+				entityStream.write(buffer);
+				off += buffer.length;
+			}
+		} catch (FilesystemAccessException e) {
+			throw new IOException("problem when reading file", e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
new file mode 100644
index 0000000..f387cf6
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FileSegmentHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static java.lang.Math.min;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.rest.FileSegment;
+
+/**
+ * How to write out a segment of a file with JAX-RS.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class FileSegmentHandler implements MessageBodyWriter<FileSegment> {
+	/** How much to pull from the worker in one read. */
+	private int maxChunkSize;
+
+	/**
+	 * @param maxChunkSize
+	 *            How much to pull from the worker in one read.
+	 */
+	public void setMaxChunkSize(int maxChunkSize) {
+		this.maxChunkSize = maxChunkSize;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return FileSegment.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public long getSize(FileSegment t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return t.to - t.from;
+	}
+
+	@Override
+	public void writeTo(FileSegment t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			int off = t.from;
+			while (off < t.to) {
+				byte[] buffer = t.file.getContents(off,
+						min(maxChunkSize, t.to - off));
+				if (buffer == null || buffer.length == 0)
+					break;
+				entityStream.write(buffer);
+				off += buffer.length;
+			}
+		} catch (FilesystemAccessException e) {
+			throw new IOException("problem when reading file", e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
new file mode 100644
index 0000000..12c137e
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/FilesystemAccessHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+
+@Provider
+public class FilesystemAccessHandler extends HandlerCore implements
+		ExceptionMapper<FilesystemAccessException> {
+	@Override
+	public Response toResponse(FilesystemAccessException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
new file mode 100644
index 0000000..775805b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/GeneralFailureHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.GeneralFailureException;
+
+public class GeneralFailureHandler extends HandlerCore implements
+		ExceptionMapper<GeneralFailureException> {
+	@Override
+	public Response toResponse(GeneralFailureException exception) {
+		return respond(INTERNAL_SERVER_ERROR, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
new file mode 100644
index 0000000..0e3fb51
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/HandlerCore.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+import static javax.ws.rs.core.Response.status;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.logging.Log;
+import org.taverna.server.master.api.ManagementModel;
+
+/**
+ * Base class for handlers that grants Spring-enabled access to the management
+ * model.
+ * 
+ * @author Donal Fellows
+ */
+public class HandlerCore {
+	private Log log = getLog("Taverna.Server.Webapp");
+	private ManagementModel managementModel;
+
+	/**
+	 * @param managementModel
+	 *            the managementModel to set
+	 */
+	public void setManagementModel(ManagementModel managementModel) {
+		this.managementModel = managementModel;
+	}
+
+	/**
+	 * Simplified interface for building responses.
+	 * 
+	 * @param status
+	 *            What status code to use?
+	 * @param exception
+	 *            What exception to report on?
+	 * @return The build response.
+	 */
+	protected Response respond(Response.Status status, Exception exception) {
+		if (managementModel.getLogOutgoingExceptions()
+				|| status.getStatusCode() >= 500)
+			log.info("converting exception to response", exception);
+		return status(status).type(TEXT_PLAIN_TYPE)
+				.entity(exception.getMessage()).build();
+	}
+
+	/**
+	 * Simplified interface for building responses.
+	 * 
+	 * @param status
+	 *            What status code to use?
+	 * @param partialMessage
+	 *            The prefix to the message.
+	 * @param exception
+	 *            What exception to report on?
+	 * @return The build response.
+	 */
+	protected Response respond(Response.Status status, String partialMessage,
+			Exception exception) {
+		if (managementModel.getLogOutgoingExceptions()
+				|| status.getStatusCode() >= 500)
+			log.info("converting exception to response", exception);
+		return status(status).type(TEXT_PLAIN_TYPE)
+				.entity(partialMessage + "\n" + exception.getMessage()).build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
new file mode 100644
index 0000000..ac02015
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/IllegalArgumentHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.UNSUPPORTED_MEDIA_TYPE;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class IllegalArgumentHandler extends HandlerCore implements
+		ExceptionMapper<IllegalArgumentException> {
+	@Override
+	public Response toResponse(IllegalArgumentException exn) {
+		return respond(UNSUPPORTED_MEDIA_TYPE, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
new file mode 100644
index 0000000..1458667
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ImplementationProblemHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.localworker.remote.ImplementationException;
+
+public class ImplementationProblemHandler extends HandlerCore implements
+		ExceptionMapper<ImplementationException> {
+	@Override
+	public Response toResponse(ImplementationException exception) {
+		return respond(INTERNAL_SERVER_ERROR, exception);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
new file mode 100644
index 0000000..2c0c092
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InputStreamMessageHandler.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010-2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static java.lang.Long.parseLong;
+import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
+import static org.apache.commons.logging.LogFactory.getLog;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Maps a stream from a client into a bounded ordinary input stream that the
+ * webapp can work with more easily.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Consumes(APPLICATION_OCTET_STREAM)
+public class InputStreamMessageHandler implements
+		MessageBodyReader<InputStream> {
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return InputStream.class.isAssignableFrom(type);
+	}
+
+	@Override
+	public InputStream readFrom(Class<InputStream> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		return new TransferStream(entityStream,
+				httpHeaders.get("Content-Length"));
+	}
+}
+
+/**
+ * The actual transfer thunk.
+ * 
+ * @author Donal Fellows
+ */
+class TransferStream extends InputStream {
+	private Log log = getLog("Taverna.Server.Handlers");
+
+	public TransferStream(InputStream entityStream, List<String> contentLength) {
+		this.entityStream = new BufferedInputStream(entityStream);
+		if (contentLength != null && contentLength.size() > 0) {
+			this.limit = parseLong(contentLength.get(0));
+			if (log.isDebugEnabled())
+				log.debug("will attempt to transfer " + this.limit + " bytes");
+		} else {
+			this.limit = -1;
+			if (log.isDebugEnabled())
+				log.debug("will attempt to transfer until EOF");
+		}
+	}
+
+	InputStream entityStream;
+	long limit;
+	long doneBytes = 0;
+
+	@Override
+	public int read() throws IOException {
+		if (limit >= 0 && doneBytes >= limit)
+			return -1;
+		int result = entityStream.read();
+		if (result >= 0)
+			doneBytes++;
+		return result;
+	}
+
+	@Override
+	public int read(byte[] ary, int off, int len) throws IOException {
+		if (limit >= 0) {
+			if (doneBytes >= limit)
+				return -1;
+			if (doneBytes + len > limit)
+				len = (int) (limit - doneBytes);
+		}
+		int readBytes = entityStream.read(ary, off, len);
+		if (readBytes >= 0)
+			doneBytes += readBytes;
+		return readBytes;
+	}
+
+	@Override
+	public void close() throws IOException {
+		entityStream.close();
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
new file mode 100644
index 0000000..fe11de8
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/InvalidCredentialHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.InvalidCredentialException;
+
+@Provider
+public class InvalidCredentialHandler extends HandlerCore implements
+		ExceptionMapper<InvalidCredentialException> {
+	@Override
+	public Response toResponse(InvalidCredentialException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
new file mode 100644
index 0000000..33ac6a0
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/JAXBExceptionHandler.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBException;
+
+@Provider
+public class JAXBExceptionHandler extends HandlerCore implements
+		ExceptionMapper<JAXBException> {
+	@Override
+	public Response toResponse(JAXBException exn) {
+		return respond(BAD_REQUEST, "APIEpicFail: " + exn.getErrorCode(), exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
new file mode 100644
index 0000000..47153e7
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NegotiationFailedHandler.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
+import static javax.ws.rs.core.Response.notAcceptable;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.rest.TavernaServerDirectoryREST.NegotiationFailedException;
+
+@Provider
+public class NegotiationFailedHandler implements
+		ExceptionMapper<NegotiationFailedException> {
+	@Override
+	public Response toResponse(NegotiationFailedException exn) {
+		return notAcceptable(exn.accepted).type(TEXT_PLAIN)
+				.entity(exn.getMessage()).build();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
new file mode 100644
index 0000000..e4215a1
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCreateHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoCreateException;
+
+@Provider
+public class NoCreateHandler extends HandlerCore implements
+		ExceptionMapper<NoCreateException> {
+	@Override
+	public Response toResponse(NoCreateException exn) {
+		return respond(SERVICE_UNAVAILABLE, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
new file mode 100644
index 0000000..d81f6ba
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoCredentialHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.NoCredentialException;
+
+public class NoCredentialHandler extends HandlerCore implements
+		ExceptionMapper<NoCredentialException> {
+	@Override
+	public Response toResponse(NoCredentialException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
new file mode 100644
index 0000000..927af4b
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDestroyHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoDestroyException;
+
+@Provider
+public class NoDestroyHandler extends HandlerCore implements
+		ExceptionMapper<NoDestroyException> {
+	@Override
+	public Response toResponse(NoDestroyException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
new file mode 100644
index 0000000..ab2e54d
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoDirectoryEntryHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoDirectoryEntryException;
+
+@Provider
+public class NoDirectoryEntryHandler extends HandlerCore implements
+		ExceptionMapper<NoDirectoryEntryException> {
+	@Override
+	public Response toResponse(NoDirectoryEntryException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
new file mode 100644
index 0000000..36e3053
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoListenerHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoListenerException;
+
+@Provider
+public class NoListenerHandler extends HandlerCore implements
+		ExceptionMapper<NoListenerException> {
+	@Override
+	public Response toResponse(NoListenerException exn) {
+		return respond(BAD_REQUEST, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
new file mode 100644
index 0000000..61a89d4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NoUpdateHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.NoUpdateException;
+
+@Provider
+public class NoUpdateHandler extends HandlerCore implements
+		ExceptionMapper<NoUpdateException> {
+	@Override
+	public Response toResponse(NoUpdateException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
new file mode 100644
index 0000000..44de871
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/NotOwnerHandler.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.FORBIDDEN;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+
+import org.taverna.server.master.exceptions.NotOwnerException;
+
+public class NotOwnerHandler extends HandlerCore implements
+		ExceptionMapper<NotOwnerException> {
+	@Override
+	public Response toResponse(NotOwnerException exn) {
+		return respond(FORBIDDEN, exn);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
new file mode 100644
index 0000000..21e5e68
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/OverloadedHandler.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.OverloadedException;
+
+@Provider
+public class OverloadedHandler extends HandlerCore implements
+		ExceptionMapper<OverloadedException> {
+	@Override
+	public Response toResponse(OverloadedException exn) {
+		return respond(SERVICE_UNAVAILABLE, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
new file mode 100644
index 0000000..03a4dd4
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/PermissionHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.taverna.server.master.common.Permission;
+
+/**
+ * Handler that allows CXF to send and receive {@linkplain Permission
+ * permissions} as plain text directly.
+ * 
+ * @author Donal Fellows
+ */
+public class PermissionHandler implements MessageBodyReader<Permission>,
+		MessageBodyWriter<Permission> {
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(Permission.class)
+				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
+	}
+
+	@Override
+	public long getSize(Permission t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return t.toString().length();
+	}
+
+	@Override
+	public void writeTo(Permission t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		new OutputStreamWriter(entityStream).write(t.toString());
+	}
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(Permission.class)
+				&& mediaType.isCompatible(TEXT_PLAIN_TYPE);
+	}
+
+	@Override
+	public Permission readFrom(Class<Permission> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		char[] cbuf = new char[7];
+		int len = new InputStreamReader(entityStream).read(cbuf);
+		if (len < 0)
+			throw new IllegalArgumentException("no entity supplied");
+		return Permission.valueOf(new String(cbuf, 0, len));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
new file mode 100644
index 0000000..edeac63
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/Scufl2DocumentHandler.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE.txt" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.common.Workflow;
+
+import uk.org.taverna.scufl2.api.io.ReaderException;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+import uk.org.taverna.scufl2.api.io.WriterException;
+
+/**
+ * Handler that allows a .scufl2 document to be read from and written to a REST
+ * message directly.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class Scufl2DocumentHandler implements MessageBodyReader<Workflow>,
+		MessageBodyWriter<Workflow> {
+	private static final MediaType SCUFL2_TYPE = new MediaType("application",
+			"vnd.taverna.scufl2.workflow-bundle");
+	public static final String SCUFL2 = "application/vnd.taverna.scufl2.workflow-bundle";
+	private WorkflowBundleIO io = new WorkflowBundleIO();
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (type.isAssignableFrom(Workflow.class))
+			return mediaType.isCompatible(SCUFL2_TYPE);
+		return false;
+	}
+
+	@Override
+	public Workflow readFrom(Class<Workflow> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		try {
+			return new Workflow(io.readBundle(entityStream, SCUFL2));
+		} catch (ReaderException e) {
+			throw new WebApplicationException(e, 403);
+		}
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (Workflow.class.isAssignableFrom(type))
+			return mediaType.isCompatible(SCUFL2_TYPE);
+		return false;
+	}
+
+	@Override
+	public long getSize(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			io.writeBundle(workflow.getScufl2Workflow(), entityStream, SCUFL2);
+		} catch (WriterException e) {
+			throw new WebApplicationException(e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
new file mode 100644
index 0000000..4227d80
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/T2FlowDocumentHandler.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.taverna.server.master.common.Workflow;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+/**
+ * Handler that allows a .t2flow document to be read from and written to a REST
+ * message directly.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+public class T2FlowDocumentHandler implements MessageBodyReader<Workflow>,
+		MessageBodyWriter<Workflow> {
+	private static final MediaType T2FLOW_TYPE = new MediaType("application",
+			"vnd.taverna.t2flow+xml");
+	public static final String T2FLOW = "application/vnd.taverna.t2flow+xml";
+	public static final String T2FLOW_ROOTNAME = "workflow";
+	public static final String T2FLOW_NS = "http://taverna.sf.net/2008/xml/t2flow";
+	private DocumentBuilderFactory db;
+	private TransformerFactory transformer;
+
+	public T2FlowDocumentHandler() throws ParserConfigurationException,
+			TransformerConfigurationException {
+		db = DocumentBuilderFactory.newInstance();
+		db.setNamespaceAware(true);
+		transformer = TransformerFactory.newInstance();
+	}
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (type.isAssignableFrom(Workflow.class))
+			return mediaType.isCompatible(T2FLOW_TYPE);
+		return false;
+	}
+
+	@Override
+	public Workflow readFrom(Class<Workflow> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		Document doc;
+		try {
+			doc = db.newDocumentBuilder().parse(entityStream);
+		} catch (SAXException e) {
+			throw new WebApplicationException(e, 403);
+		} catch (ParserConfigurationException e) {
+			throw new WebApplicationException(e);
+		}
+		Workflow workflow = new Workflow(doc.getDocumentElement());
+		if (doc.getDocumentElement().getNamespaceURI().equals(T2FLOW_NS)
+				&& doc.getDocumentElement().getNodeName()
+						.equals(T2FLOW_ROOTNAME))
+			return workflow;
+		throw new WebApplicationException(Response.status(403)
+				.entity("invalid T2flow document; bad root element")
+				.type("text/plain").build());
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		if (Workflow.class.isAssignableFrom(type))
+			return mediaType.isCompatible(T2FLOW_TYPE);
+		return false;
+	}
+
+	@Override
+	public long getSize(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(Workflow workflow, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		try {
+			transformer.newTransformer().transform(
+					new DOMSource(workflow.getT2flowWorkflow()),
+					new StreamResult(entityStream));
+		} catch (TransformerException e) {
+			if (e.getCause() != null && e.getCause() instanceof IOException)
+				throw (IOException) e.getCause();
+			throw new WebApplicationException(e);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
new file mode 100644
index 0000000..a90a229
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/URIListHandler.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.status;
+import static org.taverna.server.master.rest.handler.URIListHandler.URI_LIST;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+/**
+ * Deserialization and serialization engine for the <tt>{@value #URI_LIST}</tt>
+ * content type.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Consumes(URI_LIST)
+public class URIListHandler implements MessageBodyReader<List<URI>>,
+		MessageBodyWriter<List<URI>> {
+	/** The content type we handle. */
+	public static final String URI_LIST = "text/uri-list";
+	private static final MediaType URILIST = new MediaType("text", "uri-list");
+
+	@Override
+	public boolean isReadable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return type.isAssignableFrom(ArrayList.class)
+				&& genericType instanceof ParameterizedType
+				&& ((Class<?>) ((ParameterizedType) genericType)
+						.getActualTypeArguments()[0])
+						.isAssignableFrom(URI.class)
+				&& URILIST.isCompatible(mediaType);
+	}
+
+	@Override
+	public List<URI> readFrom(Class<List<URI>> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+			throws IOException, WebApplicationException {
+		String enc = mediaType.getParameters().get("encoding");
+		Charset c = (enc == null) ? Charset.defaultCharset() : Charset
+				.forName(enc);
+		BufferedReader br = new BufferedReader(new InputStreamReader(
+				entityStream, c));
+		ArrayList<URI> uris = new ArrayList<>();
+		String line;
+		while ((line = br.readLine()) != null) {
+			if (line.startsWith("#"))
+				continue;
+			try {
+				uris.add(new URI(line));
+			} catch (URISyntaxException e) {
+				throw new WebApplicationException(e, status(422).entity(
+						"ill-formed URI").build());
+			}
+		}
+		return uris;
+	}
+
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return List.class.isAssignableFrom(type)
+				&& genericType instanceof ParameterizedType
+				&& ((ParameterizedType) genericType).getActualTypeArguments()[0] == URI.class
+				&& URILIST.isCompatible(mediaType);
+	}
+
+	@Override
+	public long getSize(List<URI> list, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	private static final String PREFERRED_ENCODING = "UTF-8";
+
+	@Override
+	public void writeTo(List<URI> list, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException {
+		String encoding = mediaType.getParameters().get("encoding");
+		if (encoding == null) {
+			encoding = PREFERRED_ENCODING;
+			httpHeaders.putSingle("Content-Type", URI_LIST + ";encoding="
+					+ encoding);
+		}
+		BufferedWriter w = new BufferedWriter(new OutputStreamWriter(
+				entityStream, encoding));
+		for (URI uri : list) {
+			w.write(uri.toString());
+			w.newLine();
+		}
+		w.flush();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
new file mode 100644
index 0000000..4542237
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/UnknownRunHandler.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010-2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.exceptions.UnknownRunException;
+
+@Provider
+public class UnknownRunHandler extends HandlerCore implements
+		ExceptionMapper<UnknownRunException> {
+	@Override
+	public Response toResponse(UnknownRunException exn) {
+		return respond(NOT_FOUND, exn);
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
new file mode 100644
index 0000000..2241220
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/ZipStreamHandler.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.rest.handler;
+
+import static org.apache.commons.io.IOUtils.copy;
+import static org.taverna.server.master.api.ContentTypes.APPLICATION_ZIP_TYPE;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.taverna.server.master.interfaces.Directory.ZipStream;
+
+/**
+ * How to write a ZIP file as the result entity of a request.
+ * 
+ * @author Donal Fellows
+ */
+@Provider
+@Produces("application/zip")
+public class ZipStreamHandler implements MessageBodyWriter<ZipStream> {
+	@Override
+	public boolean isWriteable(Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return ZipStream.class.isAssignableFrom(type)
+				&& mediaType.equals(APPLICATION_ZIP_TYPE);
+	}
+
+	@Override
+	public long getSize(ZipStream t, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType) {
+		return -1;
+	}
+
+	@Override
+	public void writeTo(ZipStream zipStream, Class<?> type, Type genericType,
+			Annotation[] annotations, MediaType mediaType,
+			MultivaluedMap<String, Object> httpHeaders,
+			OutputStream entityStream) throws IOException,
+			WebApplicationException {
+		copy(zipStream, entityStream);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
new file mode 100644
index 0000000..e72af22
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/handler/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains type handlers for the RESTful interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.rest.handler;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
new file mode 100644
index 0000000..0a0b069
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/rest/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+/**
+ * This package contains the RESTful interface to Taverna Server.
+ * @author Donal Fellows
+ */
+@XmlSchema(namespace = SERVER_REST, elementFormDefault = QUALIFIED, attributeFormDefault = QUALIFIED, xmlns = {
+		@XmlNs(prefix = "xlink", namespaceURI = XLINK),
+		@XmlNs(prefix = "ts", namespaceURI = SERVER),
+		@XmlNs(prefix = "ts-rest", namespaceURI = SERVER_REST),
+		@XmlNs(prefix = "ts-soap", namespaceURI = SERVER_SOAP),
+		@XmlNs(prefix = "port", namespaceURI = DATA),
+		@XmlNs(prefix = "feed", namespaceURI = FEED),
+		@XmlNs(prefix = "admin", namespaceURI = ADMIN) })
+package org.taverna.server.master.rest;
+
+import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED;
+import static org.taverna.server.master.common.Namespaces.ADMIN;
+import static org.taverna.server.master.common.Namespaces.FEED;
+import static org.taverna.server.master.common.Namespaces.SERVER;
+import static org.taverna.server.master.common.Namespaces.SERVER_REST;
+import static org.taverna.server.master.common.Namespaces.SERVER_SOAP;
+import static org.taverna.server.master.common.Namespaces.XLINK;
+import static org.taverna.server.port_description.Namespaces.DATA;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
new file mode 100644
index 0000000..bb8d73f
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/DirEntry.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import static org.taverna.server.master.common.Namespaces.XLINK;
+
+import java.net.URI;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.DirEntryReference;
+
+/**
+ * A more Taverna-friendly version of the directory entry descriptor classes.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "DirectoryEntry")
+@XmlRootElement(name = "entry")
+@XmlSeeAlso({ DirEntry.File.class, DirEntry.Directory.class })
+public class DirEntry {
+	/** A link to the entry. Ignored on input. */
+	@XmlAttribute(name = "href", namespace = XLINK)
+	@XmlSchemaType(name = "anyURI")
+	public URI link;
+	@XmlAttribute
+	public String name;
+	@XmlElement(required = true)
+	public String path;
+
+	/**
+	 * A file in a directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "FileDirEntry")
+	@XmlRootElement(name = "file")
+	public static class File extends DirEntry {
+	}
+
+	/**
+	 * A directory in a directory. That is, a sub-directory.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "DirectoryDirEntry")
+	@XmlRootElement(name = "dir")
+	public static class Directory extends DirEntry {
+	}
+
+	/**
+	 * Converts from the "common" format to the subclasses of this class.
+	 * 
+	 * @param deref
+	 *            The "common" format handle to convert.
+	 * @return The converted handle
+	 */
+	public static DirEntry convert(DirEntryReference deref) {
+		DirEntry result;
+		if (deref instanceof DirEntryReference.DirectoryReference)
+			result = new Directory();
+		else if (deref instanceof DirEntryReference.FileReference)
+			result = new File();
+		else
+			result = new DirEntry();
+		result.link = deref.link;
+		result.name = deref.name;
+		result.path = deref.path;
+		return result;
+	}
+
+	/**
+	 * Converts to the "common" format from the subclasses of this class.
+	 * 
+	 * @param deref
+	 *            The subclass of this class to convert.
+	 * @return The converted reference.
+	 */
+	public static DirEntryReference convert(DirEntry de) {
+		DirEntryReference result;
+		if (de instanceof Directory)
+			result = new DirEntryReference.DirectoryReference();
+		else if (de instanceof File)
+			result = new DirEntryReference.FileReference();
+		else
+			result = new DirEntryReference();
+		result.link = de.link;
+		result.name = de.name;
+		result.path = de.path;
+		return result;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
new file mode 100644
index 0000000..7ebc991
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/FileContents.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import static java.lang.Math.min;
+import static java.lang.System.arraycopy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlMimeType;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.exceptions.FilesystemAccessException;
+import org.taverna.server.master.interfaces.File;
+
+/**
+ * An MTOM-capable description of how to transfer the contents of a file.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "FileContents")
+public class FileContents {
+	@XmlElement
+	public String name;
+	@XmlMimeType("application/octet-stream") // JAXB bug: must be this
+	public DataHandler fileData;
+
+	/**
+	 * Initialize the contents of this descriptor from the given file and
+	 * content type.
+	 * 
+	 * @param file
+	 *            The file that is to be reported.
+	 * @param contentType
+	 *            The estimated content type of the file.
+	 */
+	public void setFile(File file, String contentType) {
+		name = file.getFullName();
+		fileData = new DataHandler(new TavernaFileSource(file, contentType));
+	}
+
+	/**
+	 * Write the content described by this class to the specified file.
+	 * @param file The file to write to; must already exist.
+	 * @throws IOException
+	 * @throws FilesystemAccessException
+	 */
+	public void writeToFile(File file) throws IOException,
+			FilesystemAccessException {
+		try (InputStream is = fileData.getInputStream()) {
+			byte[] buf = new byte[65536];
+			file.setContents(new byte[0]);
+			while (true) {
+				int len = is.read(buf);
+				if (len <= 0)
+					return;
+				if (len == buf.length)
+					file.appendContents(buf);
+				else {
+					byte[] shortbuf = new byte[len];
+					arraycopy(buf, 0, shortbuf, 0, len);
+					file.appendContents(shortbuf);
+				}
+			}
+		}
+	}
+}
+
+/**
+ * A data source that knows how to communicate with the Taverna Server back-end.
+ * 
+ * @author Donal Fellows
+ */
+class TavernaFileSource implements DataSource {
+	TavernaFileSource(File f, String type) {
+		this.f = f;
+		this.type = type;
+	}
+
+	private final File f;
+	private final String type;
+
+	@Override
+	public String getContentType() {
+		return type;
+	}
+
+	@Override
+	public String getName() {
+		return f.getName();
+	}
+
+	@Override
+	public InputStream getInputStream() throws IOException {
+		final File f = this.f;
+		return new InputStream() {
+			private int idx;
+
+			@Override
+			public int read(byte[] b, int off, int len) throws IOException {
+				byte[] r;
+				try {
+					r = f.getContents(idx, len);
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+				if (r == null)
+					return -1;
+				len = min(len, r.length);
+				arraycopy(r, 0, b, off, len);
+				idx += len;
+				return len;
+			}
+
+			@Override
+			public int read() throws IOException {
+				byte[] r;
+				try {
+					r = f.getContents(idx, 1);
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+				if (r == null)
+					return -1;
+				idx++;
+				return r[0];
+			}
+		};
+	}
+
+	@Override
+	public OutputStream getOutputStream() throws IOException {
+		final File f = this.f;
+		return new OutputStream() {
+			private boolean append = false;
+
+			@Override
+			public void write(int b) throws IOException {
+				write(new byte[] { (byte) b });
+			}
+
+			@Override
+			public void write(byte[] b) throws IOException {
+				try {
+					if (append)
+						f.appendContents(b);
+					else
+						f.setContents(b);
+					append = true;
+				} catch (FilesystemAccessException e) {
+					throw new IOException(e);
+				}
+			}
+
+			@Override
+			public void write(byte[] b, int off, int len) throws IOException {
+				byte[] ary = new byte[len];
+				arraycopy(b, off, ary, 0, len);
+				write(ary);
+			}
+		};
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-server/blob/2c71f9a9/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
----------------------------------------------------------------------
diff --git a/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
new file mode 100644
index 0000000..3ab6d0c
--- /dev/null
+++ b/taverna-server-webapp/src/main/java/org/taverna/server/master/soap/PermissionList.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The University of Manchester
+ * 
+ * See the file "LICENSE" for license terms.
+ */
+package org.taverna.server.master.soap;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.taverna.server.master.common.Permission;
+
+/**
+ * The list of permissions to access a workflow run of users <i>other than the
+ * owner</i>. This class exists to support the JAXB mapping.
+ * 
+ * @author Donal Fellows
+ */
+@XmlType(name = "PermissionList")
+@XmlRootElement(name = "permissionList")
+public class PermissionList {
+	/**
+	 * The type of a single mapped permission. This class exists to support the
+	 * JAXB mapping.
+	 * 
+	 * @author Donal Fellows
+	 */
+	@XmlType(name = "")
+	public static class SinglePermissionMapping {
+		public SinglePermissionMapping() {
+		}
+
+		public SinglePermissionMapping(String user, Permission permission) {
+			this.userName = user;
+			this.permission = permission;
+		}
+
+		/** The name of the user that this talks about. */
+		public String userName;
+		/** The permission level that the user is granted. */
+		public Permission permission;
+	}
+
+	/** The list of (non-default) permissions granted. */
+	@XmlElement
+	public List<SinglePermissionMapping> permission;
+}
\ No newline at end of file