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 11:35:49 UTC

[34/58] [abbrv] incubator-taverna-plugin-component git commit: org.apache.taverna.component.*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentRegistryFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentRegistryFactory.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentRegistryFactory.java
new file mode 100644
index 0000000..e8197c1
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentRegistryFactory.java
@@ -0,0 +1,44 @@
+package org.apache.taverna.component.registry.local;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.Registry;
+import org.apache.taverna.component.registry.ComponentUtil;
+import org.apache.taverna.component.utils.SystemUtils;
+import org.springframework.beans.factory.annotation.Required;
+
+public class LocalComponentRegistryFactory {
+	private final Map<File, Registry> registries = new HashMap<>();
+	private ComponentUtil util;
+	private SystemUtils system;
+
+	@Required
+	public void setComponentUtil(ComponentUtil util) {
+		this.util = util;
+	}
+
+	@Required
+	public void setSystemUtils(SystemUtils system) {
+		this.system = system;
+	}
+
+	public synchronized Registry getComponentRegistry(File registryDir)
+			throws ComponentException {
+		if (!registries.containsKey(registryDir))
+			registries.put(registryDir, new LocalComponentRegistry(registryDir,
+					util, system));
+		return registries.get(registryDir);
+	}
+
+	public Registry getComponentRegistry(URL componentRegistryBase)
+			throws ComponentException {
+		@SuppressWarnings("deprecation")
+		String hackedPath = URLDecoder.decode(componentRegistryBase.getPath());
+		return getComponentRegistry(new File(hackedPath));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentVersion.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentVersion.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentVersion.java
new file mode 100644
index 0000000..87f19d3
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/local/LocalComponentVersion.java
@@ -0,0 +1,93 @@
+/**
+ * 
+ */
+package org.apache.taverna.component.registry.local;
+
+import static java.lang.Integer.parseInt;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.registry.local.LocalComponent.COMPONENT_FILENAME;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.registry.ComponentVersion;
+import org.apache.taverna.component.utils.SystemUtils;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ * 
+ */
+class LocalComponentVersion extends ComponentVersion {
+	private static Logger logger = getLogger(LocalComponentVersion.class);
+
+	private final File componentVersionDir;
+	private SystemUtils system;
+
+	protected LocalComponentVersion(LocalComponent component,
+			File componentVersionDir, SystemUtils system) {
+		super(component);
+		this.componentVersionDir = componentVersionDir;
+		this.system = system;
+	}
+
+	@Override
+	protected final String internalGetDescription() {
+		File descriptionFile = new File(componentVersionDir, "description");
+		try {
+			if (descriptionFile.isFile())
+				return readFileToString(descriptionFile);
+		} catch (IOException e) {
+			logger.error("failed to get description from " + descriptionFile, e);
+		}
+		return "";
+	}
+
+	@Override
+	protected final Integer internalGetVersionNumber() {
+		return parseInt(componentVersionDir.getName());
+	}
+
+	@Override
+	protected final WorkflowBundle internalGetImplementation()
+			throws ComponentException {
+		File filename = new File(componentVersionDir, COMPONENT_FILENAME);
+		try {
+			return system.getBundle(filename);
+		} catch (Exception e) {
+			logger.error(
+					"failed to get component realization from " + filename, e);
+			throw new ComponentException("Unable to open dataflow", e);
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		return 31 + ((componentVersionDir == null) ? 0 : componentVersionDir
+				.hashCode());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		LocalComponentVersion other = (LocalComponentVersion) obj;
+		if (componentVersionDir == null)
+			return (other.componentVersionDir == null);
+		return componentVersionDir.equals(other.componentVersionDir);
+	}
+
+	@Override
+	public URL getHelpURL() {
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Client.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Client.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Client.java
new file mode 100644
index 0000000..0fe6304
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Client.java
@@ -0,0 +1,637 @@
+package org.apache.taverna.component.registry.standard;
+
+import static java.lang.Math.min;
+import static java.lang.String.format;
+import static java.lang.System.getProperty;
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.URLEncoder.encode;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.registry.ClientVersion.VERSION;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.UsernamePassword;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.registry.standard.Client.MyExperimentConnector.ServerResponse;
+import org.apache.taverna.component.registry.standard.annotations.Unused;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+class Client {
+	private static final String API_VERIFICATION_RESOURCE = "/component-profiles.xml";
+	private static final String WHOAMI = "/whoami.xml";
+	private static final String PLUGIN_USER_AGENT = "Taverna2-Component-plugin/"
+			+ VERSION + " Java/" + getProperty("java.version");
+	private static final int MESSAGE_TRIM_LENGTH = 512;
+	private static final Logger logger = getLogger(Client.class);
+	private final MyExperimentConnector http;
+	private final URL registryBase;
+	private final JAXBContext jaxbContext;
+	private final CredentialManager cm;
+
+	Client(JAXBContext context, URL repository, CredentialManager cm)
+			throws ComponentException {
+		this(context, repository, true, cm);
+	}
+
+	Client(JAXBContext context, URL repository, boolean tryLogIn,
+			CredentialManager cm) throws ComponentException {
+		this.cm = cm;
+		this.registryBase = repository;
+		this.jaxbContext = context;
+		this.http = new MyExperimentConnector(tryLogIn);
+		logger.info("instantiated client connection engine to " + repository);
+	}
+
+	public boolean verify() {
+		try {
+			String url = url(API_VERIFICATION_RESOURCE);
+			logger.info("API verification: HEAD for " + url);
+			return http.HEAD(url).getCode() == HTTP_OK;
+		} catch (Exception e) {
+			logger.info("failed to connect to " + registryBase, e);
+			return false;
+		}
+	}
+
+	private String url(String uri, String... arguments)
+			throws MalformedURLException, UnsupportedEncodingException {
+		StringBuilder uriBuilder = new StringBuilder(uri);
+		for (String queryElement : arguments) {
+			String[] bits = queryElement.split("=", 2);
+			uriBuilder.append(uriBuilder.indexOf("?") < 0 ? "?" : "&")
+					.append(bits[0]).append('=')
+					.append(encode(bits[1], "UTF-8"));
+		}
+		return new URL(registryBase, uriBuilder.toString()).toString();
+	}
+
+	private Marshaller getMarshaller() throws JAXBException {
+		return jaxbContext.createMarshaller();
+	}
+
+	/**
+	 * Does an HTTP GET against the configured repository.
+	 * 
+	 * @param clazz
+	 *            The JAXB-annotated class that the result is supposed to be
+	 *            instantiated into.
+	 * @param uri
+	 *            The path part of the URI within the repository.
+	 * @param query
+	 *            The strings to put into the query part. Each should be in
+	 *            <tt>key=value</tt> form.
+	 * @return The deserialized response object.
+	 * @throws ComponentException
+	 *             If anything goes wrong.
+	 */
+	public <T> T get(Class<T> clazz, String uri, String... query)
+			throws ComponentException {
+		try {
+			int redirectCounter = 0;
+
+			String url = url(uri, query);
+			ServerResponse response;
+			do {
+				if (redirectCounter++ > 5)
+					throw new ComponentException("too many redirects!");
+				logger.info("GET of " + url);
+				response = http.GET(url);
+				if (response.isFailure())
+					throw new ComponentException(
+							"Unable to perform request (%d): %s",
+							response.getCode(), response.getError());
+			} while ((url = response.getLocation()) != null);
+			return response.getResponse(clazz);
+
+		} catch (ComponentException e) {
+			throw e;
+		} catch (MalformedURLException e) {
+			throw new ComponentException("Problem constructing resource URL", e);
+		} catch (JAXBException e) {
+			throw new ComponentException("Problem when unmarshalling response",
+					e);
+		} catch (Exception e) {
+			throw new ComponentException("Problem when sending request", e);
+		}
+	}
+
+	/**
+	 * Does an HTTP POST against the configured repository.
+	 * 
+	 * @param clazz
+	 *            The JAXB-annotated class that the result is supposed to be
+	 *            instantiated into.
+	 * @param elem
+	 *            The JAXB element to post to the resource.
+	 * @param uri
+	 *            The path part of the URI within the repository.
+	 * @param query
+	 *            The strings to put into the query part. Each should be in
+	 *            <tt>key=value</tt> form.
+	 * @return The deserialized response object.
+	 * @throws ComponentException
+	 *             If anything goes wrong.
+	 */
+	public <T> T post(Class<T> clazz, JAXBElement<?> elem, String uri,
+			String... query) throws ComponentException {
+		try {
+
+			String url = url(uri, query);
+			logger.info("POST to " + url);
+			StringWriter sw = new StringWriter();
+			getMarshaller().marshal(elem, sw);
+			if (logger.isDebugEnabled())
+				logger.info("About to post XML document:\n" + sw);
+			ServerResponse response = http.POST(url, sw);
+			if (response.isFailure())
+				throw new ComponentException(
+						"Unable to perform request (%d): %s",
+						response.getCode(), response.getError());
+			if (response.getLocation() != null)
+				return get(clazz, response.getLocation());
+			return response.getResponse(clazz);
+
+		} catch (ComponentException e) {
+			throw e;
+		} catch (MalformedURLException e) {
+			throw new ComponentException("Problem constructing resource URL", e);
+		} catch (JAXBException e) {
+			throw new ComponentException("Problem when marshalling request", e);
+		} catch (Exception e) {
+			throw new ComponentException("Problem when sending request", e);
+		}
+	}
+
+	/**
+	 * Does an HTTP PUT against the configured repository.
+	 * 
+	 * @param clazz
+	 *            The JAXB-annotated class that the result is supposed to be
+	 *            instantiated into.
+	 * @param elem
+	 *            The JAXB element to post to the resource.
+	 * @param uri
+	 *            The path part of the URI within the repository.
+	 * @param query
+	 *            The strings to put into the query part. Each should be in
+	 *            <tt>key=value</tt> form.
+	 * @return The deserialized response object.
+	 * @throws ComponentException
+	 *             If anything goes wrong.
+	 */
+	@Unused
+	public <T> T put(Class<T> clazz, JAXBElement<?> elem, String uri,
+			String... query) throws ComponentException {
+		try {
+
+			String url = url(uri, query);
+			logger.info("PUT to " + url);
+			StringWriter sw = new StringWriter();
+			getMarshaller().marshal(elem, sw);
+			if (logger.isDebugEnabled())
+				logger.info("About to put XML document:\n" + sw);
+			ServerResponse response = http.PUT(url, sw);
+			if (response.isFailure())
+				throw new ComponentException(
+						"Unable to perform request (%d): %s",
+						response.getCode(), response.getError());
+			if (response.getLocation() != null)
+				return get(clazz, response.getLocation());
+			return response.getResponse(clazz);
+
+		} catch (ComponentException e) {
+			throw e;
+		} catch (MalformedURLException e) {
+			throw new ComponentException("Problem constructing resource URL", e);
+		} catch (JAXBException e) {
+			throw new ComponentException("Problem when marshalling request", e);
+		} catch (Exception e) {
+			throw new ComponentException("Problem when sending request", e);
+		}
+	}
+
+	/**
+	 * Does an HTTP DELETE against the configured repository.
+	 * 
+	 * @param uri
+	 *            The path part of the URI within the repository.
+	 * @param query
+	 *            The strings to put into the query part. Each should be in
+	 *            <tt>key=value</tt> form.
+	 * @throws ComponentException
+	 *             If anything goes wrong.
+	 */
+	public void delete(String uri, String... query) throws ComponentException {
+		ServerResponse response;
+		try {
+
+			String url = url(uri, query);
+			logger.info("DELETE of " + url);
+			response = http.DELETE(url);
+
+		} catch (MalformedURLException e) {
+			throw new ComponentException("Problem constructing resource URL", e);
+		} catch (Exception e) {
+			throw new ComponentException("Unable to perform request", e);
+		}
+		if (response.isFailure())
+			throw new ComponentException("Unable to perform request (%d): %s",
+					response.getCode(), response.getError());
+	}
+
+	private String getCredentials(String urlString, boolean mandatory)
+			throws CMException, UnsupportedEncodingException {
+		final URI serviceURI = URI.create(urlString);
+
+		if (mandatory || cm.hasUsernamePasswordForService(serviceURI)) {
+			UsernamePassword userAndPass = cm.getUsernameAndPasswordForService(
+					serviceURI, true, null);
+			// Check for user didn't log in...
+			if (userAndPass == null)
+				return null;
+			return printBase64Binary(format("%s:%s", userAndPass.getUsername(),
+					userAndPass.getPasswordAsString()).getBytes("UTF-8"));
+		}
+		return null;
+	}
+
+	private void clearCredentials(String baseURL) throws CMException {
+		for (URI uri : cm.getServiceURIsForAllUsernameAndPasswordPairs())
+			if (uri.toString().startsWith(baseURL))
+				cm.deleteUsernameAndPasswordForService(uri);
+	}
+
+	private static Document getDocumentFromStream(InputStream inputStream)
+			throws SAXException, IOException, ParserConfigurationException {
+		DocumentBuilder db = DocumentBuilderFactory.newInstance()
+				.newDocumentBuilder();
+		Document doc;
+		try (InputStream is = new BufferedInputStream(inputStream)) {
+			if (!logger.isDebugEnabled())
+				doc = db.parse(is);
+			else {
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				copy(is, baos);
+				String response = baos.toString("UTF-8");
+				logger.info("response message follows\n"
+						+ response.substring(0,
+								min(MESSAGE_TRIM_LENGTH, response.length())));
+				doc = db.parse(new ByteArrayInputStream(baos.toByteArray()));
+			}
+		}
+		return doc;
+	}
+
+	class MyExperimentConnector {
+		// authentication settings (and the current user)
+		private String authString = null;
+
+		private void tryLogIn(boolean mandatory) throws ComponentException {
+			// check if the stored credentials are valid
+			ServerResponse response = null;
+			try {
+				String userPass = getCredentials(registryBase.toString(),
+						mandatory);
+				if (userPass == null)
+					logger.debug("no credentials available for " + registryBase);
+				else {
+					// set the system to the "logged in" state from INI file properties
+					authString = userPass;
+					response = GET(registryBase.toString() + WHOAMI);
+				}
+			} catch (Exception e) {
+				authString = null;
+				logger.debug("failed when verifying login credentials", e);
+			}
+
+			if (response == null || response.getCode() != HTTP_OK)
+				try {
+					if (response != null)
+						throw new ComponentException("failed to log in: "
+								+ response.getError());
+				} finally {
+					try {
+						authString = null;
+						clearCredentials(registryBase.toString());
+					} catch (Exception e) {
+						logger.debug("failed to clear credentials", e);
+					}
+				}
+			if (authString != null)
+				logger.debug("logged in to repository successfully");
+		}
+
+		MyExperimentConnector(boolean tryLogIn) throws ComponentException {
+			if (tryLogIn)
+				tryLogIn(false);
+		}
+
+		// getter for the current status
+		private boolean isLoggedIn() {
+			return authString != null;
+		}
+
+		private HttpURLConnection connect(String method, String strURL)
+				throws MalformedURLException, IOException {
+			HttpURLConnection conn = (HttpURLConnection) new URL(strURL)
+					.openConnection();
+			conn.setRequestMethod(method);
+			if (method.equals("POST") || method.equals("PUT"))
+				conn.setDoOutput(true);
+			conn.setRequestProperty("User-Agent", PLUGIN_USER_AGENT);
+			if (authString != null)
+				conn.setRequestProperty("Authorization", "Basic " + authString);
+			return conn;
+		}
+
+		private boolean elevate() throws ComponentException {
+			tryLogIn(true);
+			return isLoggedIn();
+		}
+
+		/**
+		 * Generic method to execute GET requests to myExperiment server.
+		 * 
+		 * @param url
+		 *            The URL on myExperiment to issue GET request to.
+		 * @return An object containing XML Document with server's response body
+		 *         and a response code. Response body XML document might be null
+		 *         if there was an error or the user wasn't authorised to
+		 *         perform a certain action. Response code will always be set.
+		 * @throws Exception
+		 */
+		public ServerResponse GET(String url) throws Exception {
+			if (!isLoggedIn())
+				logger.warn("not logged in");
+			return receiveServerResponse(connect("GET", url), url, true, false);
+		}
+
+		/**
+		 * Generic method to execute GET requests to myExperiment server.
+		 * 
+		 * @param url
+		 *            The URL on myExperiment to issue GET request to.
+		 * @return An object containing XML Document with server's response body
+		 *         and a response code. Response body XML document might be null
+		 *         if there was an error or the user wasn't authorised to
+		 *         perform a certain action. Response code will always be set.
+		 * @throws Exception
+		 */
+		public ServerResponse HEAD(String url) throws Exception {
+			if (!isLoggedIn())
+				logger.warn("not logged in");
+			return receiveServerResponse(connect("HEAD", url), url, false, true);
+		}
+
+		/**
+		 * Generic method to execute GET requests to myExperiment server.
+		 * 
+		 * @param url
+		 *            The URL on myExperiment to POST to.
+		 * @param xmlDataBody
+		 *            Body of the XML data to be POSTed to strURL.
+		 * @return An object containing XML Document with server's response body
+		 *         and a response code. Response body XML document might be null
+		 *         if there was an error or the user wasn't authorised to
+		 *         perform a certain action. Response code will always be set.
+		 * @throws Exception
+		 */
+		public ServerResponse POST(String url, Object xmlDataBody)
+				throws Exception {
+			if (!isLoggedIn() && !elevate())
+				return null;
+
+			HttpURLConnection conn = connect("POST", url);
+			sendXmlBody(xmlDataBody, conn);
+			return receiveServerResponse(conn, url, false, false);
+		}
+
+		/**
+		 * Generic method to execute DELETE requests to myExperiment server.
+		 * This is only to be called when a user is logged in.
+		 * 
+		 * @param url
+		 *            The URL on myExperiment to direct DELETE request to.
+		 * @return An object containing XML Document with server's response body
+		 *         and a response code. Response body XML document might be null
+		 *         if there was an error or the user wasn't authorised to
+		 *         perform a certain action. Response code will always be set.
+		 * @throws Exception
+		 */
+		public ServerResponse DELETE(String url) throws Exception {
+			if (!isLoggedIn() && !elevate())
+				return null;
+			return receiveServerResponse(connect("DELETE", url), url, true,
+					false);
+		}
+
+		@Unused
+		public ServerResponse PUT(String url, Object xmlDataBody)
+				throws Exception {
+			if (!isLoggedIn() && !elevate())
+				return null;
+
+			HttpURLConnection conn = connect("PUT", url);
+			sendXmlBody(xmlDataBody, conn);
+			return receiveServerResponse(conn, url, false, false);
+		}
+
+		/**
+		 * Factoring out of how to write a body.
+		 * 
+		 * @param xmlDataBody
+		 *            What to write (an {@link InputStream}, a {@link Reader} or
+		 *            an object that will have it's {@link Object#toString()
+		 *            toString()} method called.
+		 * @param conn
+		 *            Where to write it to.
+		 * @throws IOException
+		 *             If anything goes wrong. The <code>conn</code> will be
+		 *             disconnected in the case of a failure.
+		 */
+		private void sendXmlBody(Object xmlDataBody, HttpURLConnection conn)
+				throws IOException {
+			try {
+				conn.setRequestProperty("Content-Type", "application/xml");
+				if (xmlDataBody instanceof InputStream)
+					copy((InputStream) xmlDataBody, conn.getOutputStream());
+				else
+					try (OutputStreamWriter out = new OutputStreamWriter(
+							conn.getOutputStream())) {
+						if (xmlDataBody instanceof Reader)
+							copy((Reader) xmlDataBody, out);
+						else
+							out.write(xmlDataBody.toString());
+					}
+			} catch (IOException e) {
+				conn.disconnect();
+				throw e;
+			}
+		}
+
+		/**
+		 * A common method for retrieving myExperiment server's response for all
+		 * types of requests.
+		 * 
+		 * @param conn
+		 *            Instance of the established URL connection to poll for
+		 *            server's response.
+		 * @param url
+		 *            The URL on myExperiment with which the connection is
+		 *            established.
+		 * @param isGETrequest
+		 *            Flag for identifying type of the request. True when the
+		 *            current connection executes GET request; false when it
+		 *            executes a POST request.
+		 * @return An object containing XML Document with server's response body
+		 *         and a response code. Response body XML document might be null
+		 *         if there was an error or the user wasn't authorised to
+		 *         perform a certain action. Response code will always be set.
+		 */
+		private ServerResponse receiveServerResponse(HttpURLConnection conn,
+				String url, boolean isGETrequest, boolean isHEADrequest)
+				throws Exception {
+			try {
+				switch (conn.getResponseCode()) {
+				case HTTP_OK:
+					/*
+					 * data retrieval was successful - parse the response XML
+					 * and return it along with response code
+					 */
+					if (isHEADrequest)
+						return new ServerResponse(conn.getResponseCode(), null,
+								null);
+					return new ServerResponse(conn.getResponseCode(), null,
+							getDocumentFromStream(conn.getInputStream()));
+				case HTTP_NO_CONTENT:
+					return new ServerResponse(HTTP_OK, null, null);
+
+				case HttpURLConnection.HTTP_CREATED:
+				case HttpURLConnection.HTTP_MOVED_PERM:
+				case HttpURLConnection.HTTP_MOVED_TEMP:
+				case HttpURLConnection.HTTP_SEE_OTHER:
+				case HttpURLConnection.HTTP_USE_PROXY:
+					return new ServerResponse(conn.getResponseCode(),
+							conn.getHeaderField("Location"), null);
+
+				case HTTP_BAD_REQUEST:
+				case HTTP_FORBIDDEN:
+					/*
+					 * this was a bad XML request - need full XML response to
+					 * retrieve the error message from it; Java throws
+					 * IOException if getInputStream() is used when non HTTP_OK
+					 * response code was received - hence can use
+					 * getErrorStream() straight away to fetch the error
+					 * document
+					 */
+					return new ServerResponse(conn.getResponseCode(), null,
+							getDocumentFromStream(conn.getErrorStream()));
+
+				case HTTP_UNAUTHORIZED:
+					// this content is not authorised for current user
+					logger.warn("non-authorised request to " + url + "\n"
+							+ IOUtils.toString(conn.getErrorStream()));
+					return new ServerResponse(conn.getResponseCode(), null,
+							null);
+
+				case HTTP_NOT_FOUND:
+					if (isHEADrequest)
+						return new ServerResponse(conn.getResponseCode(), null,
+								null);
+					throw new FileNotFoundException("no such resource: " + url);
+				default:
+					// unexpected response code - raise an exception
+					throw new IOException(
+							format("Received unexpected HTTP response code (%d) while %s %s",
+									conn.getResponseCode(),
+									(isGETrequest ? "fetching data at"
+											: "posting data to"), url));
+				}
+			} finally {
+				conn.disconnect();
+			}
+		}
+
+		class ServerResponse {
+			private final int responseCode;
+			private final String responseLocation;
+			private final Document responseBody;
+
+			ServerResponse(int responseCode, String responseLocation,
+					Document responseBody) {
+				this.responseCode = responseCode;
+				this.responseBody = responseBody;
+				this.responseLocation = responseLocation;
+			}
+
+			public int getCode() {
+				return responseCode;
+			}
+
+			public boolean isFailure() {
+				return responseCode >= HTTP_BAD_REQUEST;
+			}
+
+			public String getLocation() {
+				return responseLocation;
+			}
+
+			public <T> T getResponse(Class<T> clazz) throws JAXBException {
+				return jaxbContext.createUnmarshaller()
+						.unmarshal(responseBody.getDocumentElement(), clazz)
+						.getValue();
+			}
+
+			/**
+			 * Returns contents of the "reason" field of the error message.
+			 */
+			public String getError() {
+				if (responseBody != null) {
+					Node reasonElement = responseBody.getDocumentElement()
+							.getElementsByTagName("reason").item(0);
+					if (reasonElement != null) {
+						String reason = reasonElement.getTextContent();
+						if (!reason.isEmpty())
+							return reason;
+					}
+				}
+				return format("unknown reason (%d)", responseCode);
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponent.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponent.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponent.java
new file mode 100644
index 0000000..7109bec
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponent.java
@@ -0,0 +1,221 @@
+package org.apache.taverna.component.registry.standard;
+
+import static java.lang.String.format;
+import static org.apache.taverna.component.registry.standard.NewComponentRegistry.logger;
+import static org.apache.taverna.component.registry.standard.Policy.getPolicy;
+import static org.apache.taverna.component.utils.SystemUtils.getElementString;
+import static org.apache.taverna.component.utils.SystemUtils.getValue;
+
+import java.lang.ref.SoftReference;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.IllegalFormatException;
+
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.Family;
+import org.apache.taverna.component.api.License;
+import org.apache.taverna.component.api.Registry;
+import org.apache.taverna.component.api.SharingPolicy;
+import org.apache.taverna.component.registry.Component;
+import org.apache.taverna.component.registry.ComponentVersion;
+import org.apache.taverna.component.registry.api.ComponentType;
+import org.apache.taverna.component.registry.api.Description;
+import org.apache.taverna.component.utils.SystemUtils;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+class NewComponent extends Component {
+	static final String ELEMENTS = "title,description";
+	static final String EXTRA = "license-type,permissions";
+
+	private final SystemUtils system;
+	final NewComponentRegistry registry;
+	final NewComponentFamily family;
+	private final String id;
+	private final String title;
+	private final String description;
+	private final String resource;
+
+	NewComponent(NewComponentRegistry registry, NewComponentFamily family,
+			Description cd, SystemUtils system) throws ComponentException {
+		super(cd.getUri());
+		this.system = system;
+		this.registry = registry;
+		this.family = family;
+		id = cd.getId().trim();
+		title = getElementString(cd, "title");
+		description = getElementString(cd, "description");
+		resource = cd.getResource();
+	}
+
+	NewComponent(NewComponentRegistry registry, NewComponentFamily family,
+			ComponentType ct, SystemUtils system) {
+		super(ct.getUri());
+		this.system = system;
+		this.registry = registry;
+		this.family = family;
+		id = ct.getId().trim();
+		title = ct.getTitle().trim();
+		description = ct.getDescription().trim();
+		resource = ct.getResource();
+	}
+
+	public ComponentType getCurrent(String elements) throws ComponentException {
+		return registry.getComponentById(id, null, elements);
+	}
+
+	@Override
+	protected String internalGetName() {
+		return title;
+	}
+
+	@Override
+	protected String internalGetDescription() {
+		return description;
+	}
+
+	@Override
+	protected void populateComponentVersionMap() {
+		try {
+			for (Description d : getCurrent("versions").getVersions()
+					.getWorkflow())
+				versionMap.put(d.getVersion(), new Version(d.getVersion(),
+						getValue(d)));
+		} catch (ComponentException e) {
+			logger.warn("failed to retrieve version list: " + e.getMessage());
+		}
+	}
+
+	@Override
+	protected Version internalAddVersionBasedOn(WorkflowBundle bundle,
+			String revisionComment) throws ComponentException {
+		/*
+		 * Only fetch the license and sharing policy now; user might have
+		 * updated them on the site and we want to duplicate.
+		 */
+		ComponentType ct = getCurrent(EXTRA);
+		License license = registry.getLicense(getValue(ct.getLicenseType())
+				.trim());
+		SharingPolicy sharingPolicy = getPolicy(ct.getPermissions());
+
+		return (Version) registry.createComponentVersionFrom(this, title,
+				revisionComment, bundle, license, sharingPolicy);
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof NewComponent) {
+			NewComponent other = (NewComponent) o;
+			return registry.equals(other.registry) && id.equals(other.id);
+		}
+		return false;
+	}
+
+	public String getResourceLocation() {
+		return resource;
+	}
+
+	private static final int BASEHASH = NewComponent.class.hashCode();
+
+	@Override
+	public int hashCode() {
+		return BASEHASH ^ registry.hashCode() ^ id.hashCode();
+	}
+
+	class Version extends ComponentVersion {
+		private int version;
+		private String description;
+		private String location;
+		private SoftReference<WorkflowBundle> bundleRef;
+
+		private static final String htmlPageTemplate = "%1$s/workflows/%2$s/versions/%3$s.html";
+
+		protected Version(Integer version, String description, WorkflowBundle bundle) {
+			super(NewComponent.this);
+			this.version = version;
+			this.description = description;
+			this.bundleRef = new SoftReference<>(bundle);
+		}
+
+		protected Version(Integer version, String description) {
+			super(NewComponent.this);
+			this.version = version;
+			this.description = description;
+		}
+
+		@Override
+		public boolean equals(Object o) {
+			if (o instanceof Version) {
+				Version other = (Version) o;
+				return version == other.version
+						&& NewComponent.this.equals(other.getComponent());
+			}
+			return false;
+		}
+
+		@Override
+		public int hashCode() {
+			return NewComponent.this.hashCode() ^ (version << 16)
+					^ (version >> 16);
+		}
+
+		@Override
+		protected Integer internalGetVersionNumber() {
+			return version;
+		}
+
+		@Override
+		protected String internalGetDescription() {
+			return description;
+		}
+
+		private String getLocationUri() throws ComponentException {
+			if (location == null)
+				location = registry.getComponentById(id, version,
+						"content-uri").getContentUri();
+			return location;
+		}
+
+		@Override
+		protected synchronized WorkflowBundle internalGetImplementation()
+				throws ComponentException {
+			if (bundleRef == null || bundleRef.get() == null) {
+				String contentUri = getLocationUri();
+				try {
+					WorkflowBundle result = system.getBundleFromUri(contentUri
+							+ "?version=" + version);
+					bundleRef = new SoftReference<>(result);
+					return result;
+				} catch (Exception e) {
+					throw new ComponentException("Unable to open dataflow", e);
+				}
+			}
+			return bundleRef.get();
+		}
+
+		@Override
+		public URL getHelpURL() {
+			try {
+				return new URL(format(htmlPageTemplate,
+						registry.getRegistryBaseString(), getId(), version));
+			} catch (IllegalFormatException | MalformedURLException e) {
+				logger.error(e);
+				return null;
+			}
+		}
+	}
+
+	@Override
+	public Registry getRegistry() {
+		return registry;
+	}
+
+	@Override
+	public Family getFamily() {
+		return family;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentFamily.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentFamily.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentFamily.java
new file mode 100644
index 0000000..ff02a33
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentFamily.java
@@ -0,0 +1,133 @@
+package org.apache.taverna.component.registry.standard;
+
+import static org.apache.taverna.component.utils.SystemUtils.getElementString;
+
+import java.util.List;
+
+import org.apache.taverna.component.api.Component;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.api.profile.Profile;
+import org.apache.taverna.component.registry.ComponentFamily;
+import org.apache.taverna.component.registry.ComponentUtil;
+import org.apache.taverna.component.registry.api.ComponentFamilyType;
+import org.apache.taverna.component.registry.api.Description;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * A family of components in the new-interface registry.
+ * 
+ * @author Donal Fellows
+ */
+class NewComponentFamily extends ComponentFamily {
+	static final String ELEMENTS = "title,description";
+
+	private final NewComponentRegistry registry;
+	private final NewComponentProfile profile;
+	private final String id;
+	private final String name;
+	private final String description;
+	private final String uri;
+	private final String resource;
+
+	NewComponentFamily(NewComponentRegistry componentRegistry,
+			NewComponentProfile profile, Description familyDesc,
+			ComponentUtil util) throws ComponentException {
+		super(componentRegistry, util);
+		uri = familyDesc.getUri();
+		registry = componentRegistry;
+		this.profile = profile;
+		id = familyDesc.getId().trim();
+		name = getElementString(familyDesc, "title");
+		description = getElementString(familyDesc, "description");
+		resource = familyDesc.getResource();
+	}
+
+	public NewComponentFamily(NewComponentRegistry componentRegistry,
+			NewComponentProfile profile, ComponentFamilyType cft,
+			ComponentUtil util) {
+		super(componentRegistry, util);
+		uri = cft.getUri();
+		registry = componentRegistry;
+		this.profile = profile;
+		id = cft.getId();
+		name = cft.getTitle();
+		description = cft.getDescription();
+		resource = cft.getResource();
+	}
+
+	@Override
+	protected String internalGetName() {
+		return name;
+	}
+
+	@Override
+	protected String internalGetDescription() {
+		return description;
+	}
+
+	@Override
+	protected Profile internalGetComponentProfile() throws ComponentException {
+		return profile;
+	}
+
+	public List<Component> getMemberComponents() throws ComponentException {
+		return registry.listComponents(this);
+	}
+
+	@Override
+	protected void populateComponentCache() throws ComponentException {
+		for (Component c : getMemberComponents()) {
+			NewComponent component = (NewComponent) c;
+			componentCache.put(component.getName(), component);
+		}
+	}
+
+	@Override
+	protected Version internalCreateComponentBasedOn(String componentName,
+			String description, WorkflowBundle bundle) throws ComponentException {
+		if (componentName == null)
+			componentName = registry.annUtils.getTitle(bundle, "Untitled");
+		if (description == null)
+			componentName = registry.annUtils.getDescription(bundle,
+					"Undescribed");
+		return registry.createComponentFrom(this, componentName, description,
+				bundle, registry.getPreferredLicense(),
+				registry.getDefaultSharingPolicy());
+	}
+
+	@Override
+	protected void internalRemoveComponent(Component component)
+			throws ComponentException {
+		registry.deleteComponent((NewComponent) component);
+	}
+
+	String getId() {
+		return id;
+	}
+
+	public String getUri() {
+		return uri;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof NewComponentFamily) {
+			NewComponentFamily other = (NewComponentFamily) o;
+			return registry.equals(other.registry) && id.equals(other.id);
+		}
+		return false;
+	}
+
+	private static final int BASEHASH = NewComponentFamily.class.hashCode();
+
+	@Override
+	public int hashCode() {
+		return BASEHASH ^ registry.hashCode() ^ id.hashCode();
+	}
+
+	public String getResourceLocation() {
+		return resource;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentLicense.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentLicense.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentLicense.java
new file mode 100644
index 0000000..ddb87c0
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentLicense.java
@@ -0,0 +1,58 @@
+package org.apache.taverna.component.registry.standard;
+
+import org.apache.taverna.component.api.License;
+import org.apache.taverna.component.registry.api.LicenseType;
+
+class NewComponentLicense implements License {
+	private NewComponentRegistry registry;
+	private String id;
+	private String title;
+	private String description;
+	private String abbreviation;
+
+	static final String ELEMENTS = "title,description,unique-name";
+
+	NewComponentLicense(NewComponentRegistry newComponentRegistry,
+			LicenseType lt) {
+		registry = newComponentRegistry;
+		id = lt.getId();
+		title = lt.getTitle();
+		description = lt.getDescription();
+		abbreviation = lt.getUniqueName();
+	}
+
+	String getId() {
+		return id;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (!(o instanceof NewComponentLicense))
+			return false;
+		NewComponentLicense other = (NewComponentLicense) o;
+		return registry.equals(other.registry) && id.equals(other.id);
+	}
+
+	private static final int BASEHASH = NewComponentLicense.class.hashCode();
+
+	@Override
+	public int hashCode() {
+		return BASEHASH ^ registry.hashCode() ^ id.hashCode();
+	}
+
+	@Override
+	public String getName() {
+		return title;
+	}
+
+	@Override
+	public String getDescription() {
+		return description;
+	}
+
+	@Override
+	public String getAbbreviation() {
+		return abbreviation;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentProfile.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentProfile.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentProfile.java
new file mode 100644
index 0000000..cade980
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentProfile.java
@@ -0,0 +1,103 @@
+package org.apache.taverna.component.registry.standard;
+
+import static org.apache.taverna.component.utils.SystemUtils.getElementString;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.profile.BaseProfileLocator;
+import org.apache.taverna.component.profile.ComponentProfileImpl;
+import org.apache.taverna.component.registry.api.ComponentProfileType;
+import org.apache.taverna.component.registry.api.Description;
+
+/**
+ * Profiles managed by the new-interface component registry.
+ * 
+ * @author Donal Fellows
+ */
+class NewComponentProfile extends ComponentProfileImpl {
+	private static final String LOCATION = "content-uri";
+	static final String ELEMENTS = LOCATION;
+
+	private final NewComponentRegistry registry;
+	private String id;
+	private String location;
+	private String resource;
+	private final String uri;
+
+	private static URL contentUrl(ComponentProfileType cpt)
+			throws ComponentException {
+		try {
+			return new URL(cpt.getContentUri());
+		} catch (MalformedURLException e) {
+			throw new ComponentException("bad profile location", e);
+		}
+	}
+
+	private static URL getLocationURL(Description cpd) throws ComponentException {
+		try {
+			return new URL(getElementString(cpd, LOCATION));
+		} catch (MalformedURLException e) {
+			throw new ComponentException("bad profile location", e);
+		}
+	}
+
+	NewComponentProfile(NewComponentRegistry registry,
+			ComponentProfileType profile, BaseProfileLocator base)
+			throws ComponentException {
+		super(registry, contentUrl(profile), base);
+		this.registry = registry;
+		uri = profile.getUri();
+		id = profile.getId();
+		location = profile.getContentUri();
+		resource = profile.getResource();
+	}
+
+	NewComponentProfile(NewComponentRegistry registry, Description cpd,
+			BaseProfileLocator base) throws ComponentException {
+		super(registry, getLocationURL(cpd), base);
+		this.registry = registry;
+		uri = cpd.getUri();
+		id = cpd.getId();
+		location = getElementString(cpd, LOCATION);
+		resource = cpd.getResource();
+	}
+
+	public String getLocation() {
+		return location;
+	}
+
+	public String getID() {
+		return id;
+	}
+
+	public String getUri() {
+		return uri;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof NewComponentProfile) {
+			NewComponentProfile other = (NewComponentProfile) o;
+			return registry.equals(other.registry) && id.equals(other.id);
+		}
+		return false;
+	}
+
+	private static final int BASEHASH = NewComponentProfile.class.hashCode();
+
+	@Override
+	public int hashCode() {
+		return BASEHASH ^ registry.hashCode() ^ id.hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return "Remote Component Profile[" + location + "]";
+	}
+
+	public String getResourceLocation() {
+		return resource;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistry.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistry.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistry.java
new file mode 100644
index 0000000..b8d46f1
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistry.java
@@ -0,0 +1,469 @@
+package org.apache.taverna.component.registry.standard;
+
+import static org.apache.log4j.Logger.getLogger;
+import static org.apache.taverna.component.registry.standard.Policy.PRIVATE;
+import static org.apache.taverna.component.utils.SystemUtils.getElementString;
+
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.component.api.Component;
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.api.Family;
+import org.apache.taverna.component.api.License;
+import org.apache.taverna.component.api.SharingPolicy;
+import org.apache.taverna.component.api.Version;
+import org.apache.taverna.component.api.Version.ID;
+import org.apache.taverna.component.api.profile.Profile;
+import org.apache.taverna.component.registry.ComponentRegistry;
+import org.apache.taverna.component.registry.ComponentUtil;
+import org.apache.taverna.component.registry.ComponentVersionIdentification;
+import org.apache.taverna.component.registry.api.ComponentDescriptionList;
+import org.apache.taverna.component.registry.api.ComponentFamilyList;
+import org.apache.taverna.component.registry.api.ComponentFamilyType;
+import org.apache.taverna.component.registry.api.ComponentProfileList;
+import org.apache.taverna.component.registry.api.ComponentProfileType;
+import org.apache.taverna.component.registry.api.ComponentType;
+import org.apache.taverna.component.registry.api.Content;
+import org.apache.taverna.component.registry.api.Description;
+import org.apache.taverna.component.registry.api.LicenseList;
+import org.apache.taverna.component.registry.api.LicenseType;
+import org.apache.taverna.component.registry.api.ObjectFactory;
+import org.apache.taverna.component.registry.api.Permissions;
+import org.apache.taverna.component.registry.api.PolicyList;
+import org.apache.taverna.component.utils.AnnotationUtils;
+import org.apache.taverna.component.utils.SystemUtils;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+class NewComponentRegistry extends ComponentRegistry {
+	private static final String PROFILE_MIME_TYPE = "application/vnd.taverna.component-profile+xml";
+	private static final String T2FLOW_MIME_TYPE = "application/vnd.taverna.t2flow+xml";
+	static final Logger logger = getLogger(NewComponentRegistry.class);
+	static final JAXBContext jaxbContext;
+	static final Charset utf8;
+	private static final ObjectFactory objectFactory = new ObjectFactory();
+
+	// service URIs
+	private static final String COMPONENT_SERVICE = "/component.xml";
+	private static final String COMPONENT_FAMILY_SERVICE = "/component-family.xml";
+	private static final String COMPONENT_PROFILE_SERVICE = "/component-profile.xml";
+	private static final String COMPONENT_LIST = "/components.xml";
+	private static final String COMPONENT_FAMILY_LIST = "/component-families.xml";
+	private static final String COMPONENT_PROFILE_LIST = "/component-profiles.xml";
+	private static final String WORKFLOW_SERVICE = "/workflow.xml";
+	private static final String PACK_SERVICE = "/pack.xml";
+	private static final String FILE_SERVICE = "/file.xml";
+	private static final String LICENSE_LIST = "/licenses.xml";
+	private static final String POLICY_LIST = "/policies.xml";
+
+	static {
+		JAXBContext c = null;
+		Charset cs = null;
+		try {
+			c = JAXBContext.newInstance(ComponentDescriptionList.class,
+					ComponentFamilyList.class, ComponentProfileList.class,
+					ComponentType.class, ComponentFamilyType.class,
+					ComponentProfileType.class, PolicyList.class,
+					LicenseList.class);
+			cs = Charset.forName("UTF-8");
+		} catch (JAXBException e) {
+			throw new Error("failed to build context", e);
+		} catch (UnsupportedCharsetException e) {
+			throw new Error("failed to find charset", e);
+		} finally {
+			jaxbContext = c;
+			utf8 = cs;
+		}
+	}
+
+	Client client;
+	private final CredentialManager cm;
+	private final ComponentUtil util;
+	private final SystemUtils system;
+	final AnnotationUtils annUtils;
+
+	protected NewComponentRegistry(CredentialManager cm, URL registryBase,
+			ComponentUtil util, SystemUtils system, AnnotationUtils annUtils) throws ComponentException {
+		super(registryBase);
+		this.cm = cm;
+		this.util = util;
+		this.system = system;
+		this.annUtils = annUtils;
+	}
+
+	private void checkClientCreated() throws ComponentException {
+		try {
+			if (client == null)
+				client = new Client(jaxbContext, super.getRegistryBase(), cm);
+		} catch (Exception e) {
+			throw new ComponentException("Unable to access registry", e);
+		}
+	}
+
+	private List<Description> listComponentFamilies(String profileUri)
+			throws ComponentException {
+		checkClientCreated();
+		return client.get(ComponentFamilyList.class, COMPONENT_FAMILY_LIST,
+				"component-profile=" + profileUri,
+				"elements=" + NewComponentFamily.ELEMENTS).getPack();
+	}
+
+	ComponentType getComponentById(String id, Integer version, String elements)
+			throws ComponentException {
+		checkClientCreated();
+
+		if (version != null) {
+			return client.get(ComponentType.class, WORKFLOW_SERVICE,
+					"id=" + id, "version=" + version, "elements=" + elements);
+		}
+		return client.get(ComponentType.class, WORKFLOW_SERVICE, "id=" + id,
+				"elements=" + elements);
+	}
+
+	@SuppressWarnings("unused")
+	private ComponentFamilyType getComponentFamilyById(String id,
+			String elements) throws ComponentException {
+		checkClientCreated();
+
+		return client.get(ComponentFamilyType.class, PACK_SERVICE, "id=" + id,
+				"elements=" + elements);
+	}
+
+	private ComponentProfileType getComponentProfileById(String id,
+			String elements) throws ComponentException {
+		checkClientCreated();
+
+		return client.get(ComponentProfileType.class, FILE_SERVICE, "id=" + id,
+				"elements=" + elements);
+	}
+
+	@Override
+	protected void populateFamilyCache() throws ComponentException {
+		for (Profile pr : getComponentProfiles()) {
+			NewComponentProfile p = (NewComponentProfile) pr;
+			for (Description cfd : listComponentFamilies(p
+					.getResourceLocation()))
+				familyCache.put(getElementString(cfd, "title"),
+						new NewComponentFamily(this, p, cfd, util));
+		}
+	}
+
+	@Override
+	protected Family internalCreateComponentFamily(String familyName,
+			Profile componentProfile, String description, License license,
+			SharingPolicy sharingPolicy) throws ComponentException {
+		NewComponentProfile profile = (NewComponentProfile) componentProfile;
+
+		checkClientCreated();
+
+		return new NewComponentFamily(this, profile, client.post(
+				ComponentFamilyType.class,
+				objectFactory.createPack(makeComponentFamilyCreateRequest(
+						profile, familyName, description, license,
+						sharingPolicy)), COMPONENT_FAMILY_SERVICE, "elements="
+						+ NewComponentFamily.ELEMENTS), util);
+	}
+
+	@Override
+	protected void internalRemoveComponentFamily(Family componentFamily)
+			throws ComponentException {
+		NewComponentFamily ncf = (NewComponentFamily) componentFamily;
+		checkClientCreated();
+
+		client.delete(WORKFLOW_SERVICE, "id=" + ncf.getId());
+	}
+
+	@Override
+	protected void populateProfileCache() throws ComponentException {
+		checkClientCreated();
+
+		for (Description cpd : client.get(ComponentProfileList.class,
+				COMPONENT_PROFILE_LIST,
+				"elements=" + NewComponentProfile.ELEMENTS).getFile())
+			if (cpd.getUri() != null && !cpd.getUri().isEmpty())
+				profileCache.add(new NewComponentProfile(this, cpd, util
+						.getBaseProfileLocator()));
+	}
+
+	@Override
+	protected Profile internalAddComponentProfile(Profile componentProfile,
+			License license, SharingPolicy sharingPolicy)
+			throws ComponentException {
+		if (componentProfile == null)
+			throw new ComponentException("component profile must not be null");
+		try {
+			if (componentProfile instanceof NewComponentProfile) {
+				NewComponentProfile profile = (NewComponentProfile) componentProfile;
+				if (profile.getComponentRegistry().equals(this))
+					return new NewComponentProfile(this,
+							getComponentProfileById(profile.getId(),
+									NewComponentProfile.ELEMENTS),
+							util.getBaseProfileLocator());
+			}
+		} catch (ComponentException e) {
+			// Do nothing but fall through
+		}
+		checkClientCreated();
+
+		return new NewComponentProfile(this, client.post(
+				ComponentProfileType.class, objectFactory
+						.createFile(makeComponentProfileCreateRequest(
+								componentProfile.getName(),
+								componentProfile.getDescription(),
+								componentProfile.getXML(), license,
+								sharingPolicy)), COMPONENT_PROFILE_SERVICE,
+				"elements=" + NewComponentProfile.ELEMENTS),
+				util.getBaseProfileLocator());
+	}
+
+	public Permissions getPermissions(SharingPolicy userSharingPolicy) {
+		if (userSharingPolicy == null)
+			userSharingPolicy = getDefaultSharingPolicy();
+		return ((Policy) userSharingPolicy).getPermissionsElement();
+	}
+
+	private ComponentProfileType makeComponentProfileCreateRequest(
+			String title, String description, String content, License license,
+			SharingPolicy sharingPolicy) throws ComponentException {
+		ComponentProfileType profile = new ComponentProfileType();
+
+		profile.setFilename(title + ".xml");
+		profile.setTitle(title);
+		profile.setTitle(description);
+		profile.setContentType(PROFILE_MIME_TYPE);
+		profile.setContent(new Content());
+		profile.getContent().setEncoding("base64");
+		profile.getContent().setType("binary");
+		profile.getContent().setValue(content.getBytes(utf8));
+		if (license == null)
+			license = getPreferredLicense();
+		profile.setLicenseType(new Description());
+		profile.getLicenseType().getContent().add(license.getAbbreviation());
+		profile.setPermissions(getPermissions(sharingPolicy));
+
+		return profile;
+	}
+
+	private ComponentFamilyType makeComponentFamilyCreateRequest(
+			NewComponentProfile profile, String familyName, String description,
+			License license, SharingPolicy sharingPolicy)
+			throws ComponentException {
+		ComponentFamilyType familyDoc = new ComponentFamilyType();
+
+		familyDoc.setComponentProfile(profile.getResourceLocation());
+		familyDoc.setDescription(description);
+		familyDoc.setTitle(familyName);
+		if (license == null)
+			license = getPreferredLicense();
+		familyDoc.setLicenseType(new Description());
+		familyDoc.getLicenseType().getContent().add(license.getAbbreviation());
+		familyDoc.setPermissions(getPermissions(sharingPolicy));
+
+		return familyDoc;
+	}
+
+	private ComponentType makeComponentVersionCreateRequest(String title,
+			String description, WorkflowBundle content, NewComponentFamily family,
+			License license, SharingPolicy sharingPolicy)
+			throws ComponentException {
+		ComponentType comp = new ComponentType();
+
+		comp.setTitle(title);
+		comp.setDescription(description);
+		if (family != null)
+			comp.setComponentFamily(family.getResourceLocation());
+		comp.setContentType(T2FLOW_MIME_TYPE);
+		comp.setContent(new Content());
+		comp.getContent().setEncoding("base64");
+		comp.getContent().setType("binary");
+		comp.getContent().setValue(system.serializeBundle(content));
+		if (license == null)
+			license = getPreferredLicense();
+		if (license != null) {
+			comp.setLicenseType(new Description());
+			comp.getLicenseType().getContent().add(license.getAbbreviation());
+		}
+		comp.setPermissions(getPermissions(sharingPolicy));
+
+		return comp;
+	}
+
+	private static final boolean DO_LIST_POLICIES = false;
+
+	private List<Description> listPolicies() throws ComponentException {
+		checkClientCreated();
+		return client.get(PolicyList.class, POLICY_LIST, "type=group")
+				.getPolicy();
+	}
+
+	@Override
+	protected void populatePermissionCache() {
+		permissionCache.add(Policy.PUBLIC);
+		permissionCache.add(Policy.PRIVATE);
+		try {
+			if (DO_LIST_POLICIES)
+				for (Description d : listPolicies())
+					permissionCache.add(new Policy.Group(d.getId()));
+		} catch (ComponentException e) {
+			logger.warn("failed to fetch sharing policies", e);
+		}
+	}
+
+	private List<LicenseType> listLicenses() throws ComponentException {
+		checkClientCreated();
+
+		return client.get(LicenseList.class, LICENSE_LIST,
+				"elements=" + NewComponentLicense.ELEMENTS).getLicense();
+	}
+
+	@Override
+	protected void populateLicenseCache() {
+		try {
+			for (LicenseType lt : listLicenses())
+				licenseCache.add(new NewComponentLicense(this, lt));
+		} catch (ComponentException e) {
+			logger.warn("failed to fetch licenses", e);
+		}
+	}
+
+	@Override
+	public License getPreferredLicense() throws ComponentException {
+		return getLicenseByAbbreviation(getNameOfPreferredLicense());
+	}
+
+	public String getNameOfPreferredLicense() {
+		return "by-nd";
+	}
+
+	public SharingPolicy getDefaultSharingPolicy() {
+		return PRIVATE;
+	}
+
+	private List<Description> listComponents(String query, String prefixes)
+			throws ComponentException {
+		checkClientCreated();
+
+		return client.get(ComponentDescriptionList.class, COMPONENT_LIST,
+				"query=" + query, "prefixes=" + prefixes,
+				"elements=" + NewComponent.ELEMENTS).getWorkflow();
+	}
+
+	@Override
+	public Set<ID> searchForComponents(String prefixes, String text)
+			throws ComponentException {
+		HashSet<ID> versions = new HashSet<>();
+		for (Description cd : listComponents(text, prefixes)) {
+			NewComponent nc = null;
+			for (Family f : getComponentFamilies()) {
+				nc = (NewComponent) ((NewComponentFamily) f)
+						.getComponent(getElementString(cd, "title"));
+				if (nc != null)
+					break;
+			}
+			if (nc != null)
+				versions.add(new ComponentVersionIdentification(
+						getRegistryBase(), nc.getFamily().getName(), nc
+								.getName(), cd.getVersion()));
+			else
+				logger.warn("could not construct component for " + cd.getUri());
+		}
+		return versions;
+	}
+
+	private List<Description> listComponents(String familyUri)
+			throws ComponentException {
+		checkClientCreated();
+
+		return client.get(ComponentDescriptionList.class, COMPONENT_LIST,
+				"component-family=" + familyUri,
+				"elements=" + NewComponent.ELEMENTS).getWorkflow();
+	}
+
+	protected List<Component> listComponents(NewComponentFamily family)
+			throws ComponentException {
+		List<Component> result = new ArrayList<>();
+		for (Description cd : listComponents(family.getResourceLocation()))
+			result.add(new NewComponent(this, family, cd, system));
+		return result;
+	}
+
+	protected void deleteComponent(NewComponent component)
+			throws ComponentException {
+		checkClientCreated();
+
+		client.delete(WORKFLOW_SERVICE, "id=" + component.getId());
+	}
+
+	protected Version createComponentFrom(NewComponentFamily family,
+			String componentName, String description,
+			WorkflowBundle implementation, License license,
+			SharingPolicy sharingPolicy) throws ComponentException {
+		checkClientCreated();
+
+		ComponentType ct = client.post(ComponentType.class, objectFactory
+				.createWorkflow(makeComponentVersionCreateRequest(
+						componentName, description, implementation, family,
+						license, sharingPolicy)), COMPONENT_SERVICE,
+				"elements=" + NewComponent.ELEMENTS);
+		NewComponent nc = new NewComponent(this, family, ct, system);
+		return nc.new Version(ct.getVersion(), description, implementation);
+	}
+
+	protected Version createComponentVersionFrom(NewComponent component,
+			String componentName, String description,
+			WorkflowBundle implementation, License license,
+			SharingPolicy sharingPolicy) throws ComponentException {
+		checkClientCreated();
+
+		ComponentType ct = client.post(ComponentType.class, objectFactory
+				.createWorkflow(makeComponentVersionCreateRequest(
+						componentName, description, implementation,
+						component.family, license, sharingPolicy)),
+				COMPONENT_SERVICE, "id=" + component.getId(), "elements="
+						+ NewComponent.ELEMENTS);
+		return component.new Version(ct.getVersion(), description,
+				implementation);
+	}
+
+	public License getLicense(String name) throws ComponentException {
+		for (License l : getLicenses())
+			if (l.getAbbreviation().equals(name))
+				return l;
+		return null;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		// Careful! Java's URL equality IS BROKEN!
+		if (o != null && o instanceof NewComponentRegistry) {
+			NewComponentRegistry other = (NewComponentRegistry) o;
+			return getRegistryBaseString()
+					.equals(other.getRegistryBaseString());
+		}
+		return false;
+	}
+
+	private static final int BASEHASH = NewComponentRegistry.class.hashCode();
+
+	@Override
+	public int hashCode() {
+		return BASEHASH ^ getRegistryBaseString().hashCode();
+	}
+
+	@Override
+	public String getRegistryTypeName() {
+		return "Component API";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistryFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistryFactory.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistryFactory.java
new file mode 100644
index 0000000..04075ad
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/NewComponentRegistryFactory.java
@@ -0,0 +1,66 @@
+package org.apache.taverna.component.registry.standard;
+
+import static org.apache.taverna.component.registry.standard.NewComponentRegistry.jaxbContext;
+import static org.apache.taverna.component.registry.standard.NewComponentRegistry.logger;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.registry.ComponentRegistry;
+import org.apache.taverna.component.registry.ComponentUtil;
+import org.apache.taverna.component.utils.AnnotationUtils;
+import org.apache.taverna.component.utils.SystemUtils;
+import org.springframework.beans.factory.annotation.Required;
+
+public class NewComponentRegistryFactory {
+	private final Map<String, NewComponentRegistry> componentRegistries = new HashMap<>();
+	private CredentialManager cm;
+	private ComponentUtil util;
+	private SystemUtils system;
+	private AnnotationUtils annUtils;
+
+	@Required
+	public void setCredentialManager(CredentialManager cm) {
+		this.cm = cm;
+	}
+
+	@Required
+	public void setComponentUtil(ComponentUtil util) {
+		this.util = util;
+	}
+
+	@Required
+	public void setSystemUtils(SystemUtils system) {
+		this.system = system;
+	}
+
+	@Required
+	public void setAnnotationUtils(AnnotationUtils annUtils) {
+		this.annUtils = annUtils;
+	}
+
+	public synchronized ComponentRegistry getComponentRegistry(URL registryBase)
+			throws ComponentException {
+		if (!componentRegistries.containsKey(registryBase.toExternalForm())) {
+			logger.debug("constructing registry instance for " + registryBase);
+			componentRegistries.put(registryBase.toExternalForm(),
+					new NewComponentRegistry(cm, registryBase, util, system,
+							annUtils));
+		}
+		return componentRegistries.get(registryBase.toExternalForm());
+	}
+
+	public boolean verifyBase(URL registryBase) {
+		try {
+			return new Client(jaxbContext, registryBase, false, cm).verify();
+		} catch (Exception e) {
+			logger.info("failed to construct connection client to "
+					+ registryBase, e);
+			return false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Policy.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Policy.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Policy.java
new file mode 100644
index 0000000..74b9496
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/Policy.java
@@ -0,0 +1,136 @@
+package org.apache.taverna.component.registry.standard;
+
+import static java.lang.System.identityHashCode;
+import static org.apache.taverna.component.registry.api.Privilege.DOWNLOAD;
+import static org.apache.taverna.component.registry.api.Privilege.VIEW;
+
+import org.apache.taverna.component.api.SharingPolicy;
+import org.apache.taverna.component.registry.api.Permissions;
+import org.apache.taverna.component.registry.api.Permissions.Permission;
+
+abstract class Policy implements SharingPolicy {
+	public static final SharingPolicy PUBLIC = new Public();
+	public static final SharingPolicy PRIVATE = new Private();
+
+	Policy() {
+	}
+
+	public abstract Permissions getPermissionsElement();
+
+	public static SharingPolicy getPolicy(Permissions perm) {
+		if (perm == null)
+			return PRIVATE;
+		if (perm.getGroupPolicyId() != null)
+			return new Group(perm.getGroupPolicyId());
+		for (Permission p : perm.getPermission())
+			if (p.getId() != null)
+				return new Group(p.getId().toString(), perm);
+		return PUBLIC;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o == null || !(o instanceof Policy))
+			return false;
+		return equals((Policy) o);
+	}
+
+	@Override
+	public abstract int hashCode();
+
+	protected abstract boolean equals(Policy p);
+
+	static class Public extends Policy {
+		@Override
+		public String getName() {
+			return "Public";
+		}
+
+		@Override
+		public Permissions getPermissionsElement() {
+			Permission.Privilege privView = new Permission.Privilege();
+			privView.setType(VIEW);
+			Permission.Privilege privDownload = new Permission.Privilege();
+			privDownload.setType(DOWNLOAD);
+			Permission perm = new Permission();
+			perm.setCategory("public");
+			perm.getPrivilege().add(privView);
+			perm.getPrivilege().add(privDownload);
+			Permissions result = new Permissions();
+			result.getPermission().add(perm);
+			return result;
+		}
+
+		@Override
+		protected boolean equals(Policy p) {
+			return p instanceof Public;
+		}
+
+		@Override
+		public int hashCode() {
+			return identityHashCode(PUBLIC);
+		}
+	}
+
+	static class Private extends Policy {
+		@Override
+		public String getName() {
+			return "Private";
+		}
+
+		@Override
+		public Permissions getPermissionsElement() {
+			return null;
+		}
+
+		@Override
+		protected boolean equals(Policy p) {
+			return p instanceof Private;
+		}
+
+		@Override
+		public int hashCode() {
+			return identityHashCode(PRIVATE);
+		}
+	}
+
+	static class Group extends Policy {
+		private String id;
+		private Permissions p;
+
+		public Group(String id) {
+			this.id = id;
+		}
+
+		public Group(String id, Permissions p) {
+			this.id = id;
+			this.p = p;
+		}
+
+		@Override
+		public String getName() {
+			return "Group(" + id + ")";
+		}
+
+		@Override
+		public Permissions getPermissionsElement() {
+			if (p != null)
+				return p;
+			Permissions result = new Permissions();
+			result.setGroupPolicyId(id);
+			return result;
+		}
+
+		@Override
+		protected boolean equals(Policy p) {
+			return (p instanceof Group) && id.equals(((Group) p).id);
+		}
+
+		private static final int BASEHASH = Group.class.hashCode();
+
+		@Override
+		public int hashCode() {
+			return BASEHASH ^ id.hashCode();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/Unused.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/Unused.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/Unused.java
new file mode 100644
index 0000000..4b6fe39
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/Unused.java
@@ -0,0 +1,25 @@
+package org.apache.taverna.component.registry.standard.annotations;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a constructor, field, method or parameter as unused. Unused members
+ * exist for the purpose of documentation or completeness.
+ * 
+ * @author Donal Fellows
+ */
+@Documented
+@Target({ CONSTRUCTOR, FIELD, METHOD, PARAMETER, TYPE })
+@Retention(CLASS)
+public @interface Unused {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/package-info.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/package-info.java
new file mode 100644
index 0000000..ca6704f
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/annotations/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Miscellaneous annotations on other parts of the component engine.
+ *
+ * @author Donal Fellows
+ */
+package org.apache.taverna.component.registry.standard.annotations;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/package-info.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/package-info.java
new file mode 100644
index 0000000..43a53f7
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/registry/standard/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This is the new interface to the myExperiment registry, a.k.a. &mu;Experiment.
+ * @author Donal Fellows
+ */
+package org.apache.taverna.component.registry.standard;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/AnnotationUtils.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/AnnotationUtils.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/AnnotationUtils.java
new file mode 100644
index 0000000..2e886de
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/AnnotationUtils.java
@@ -0,0 +1,91 @@
+package org.apache.taverna.component.utils;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.WeakHashMap;
+
+import uk.org.taverna.scufl2.api.annotation.Annotation;
+import uk.org.taverna.scufl2.api.common.Child;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.common.URITools;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.ucfpackage.UCFPackage.ResourceEntry;
+
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.rdf.model.Property;
+import com.hp.hpl.jena.rdf.model.Statement;
+
+public class AnnotationUtils {
+	private static final String TITLE_ANNOTATION = "http://purl.org/dc/terms/title";
+	private static final String DESCRIPTION_ANNOTATION = "http://purl.org/dc/terms/description";
+	private Scufl2Tools tools = new Scufl2Tools();
+	private URITools uris = new URITools();
+
+	public Model getAnnotationModel(Child<WorkflowBundle> subject) throws IOException {
+		return ModelFactory.createDefaultModel().add(getModel(subject));
+	}
+
+	private WeakHashMap<Child<?>, Model> cache = new WeakHashMap<>();
+
+	private static void readParse(Model model, WorkflowBundle bundle, String path)
+			throws IOException {
+		model.read(
+				new StringReader(bundle.getResources()
+						.getResourceAsString(path)), bundle.getGlobalBaseURI()
+						.resolve(path).toString(), "TTL");
+	}
+
+	public Model getModel(Child<WorkflowBundle> subject) throws IOException {
+		WorkflowBundle bundle = subject.getParent();
+		Model m = cache.get(subject);
+		if (m == null) {
+			m = ModelFactory.createDefaultModel();
+			long initialSize = m.size();
+			for (Annotation a : tools.annotationsFor(subject,
+					subject.getParent()))
+				if (!a.getBody().isAbsolute())
+					readParse(m, bundle, a.getBody().getPath());
+			if (m.size() == initialSize)
+				for (ResourceEntry o : bundle.getResources()
+						.listResources("annotation").values())
+					readParse(m, bundle, o.getPath());
+			cache.put(subject, m);
+		}
+		return m;
+	}
+
+	public Statement getAnnotation(Child<WorkflowBundle> subject,
+			String uriForAnnotation) throws IOException {
+		Model m = getModel(subject);
+		Property p = m.getProperty(uriForAnnotation);
+		return m.getResource(uris.uriForBean(subject).toString()).getProperty(
+				p);
+	}
+
+	/** Get the title of the main workflow in a workflow bundle. */
+	public String getTitle(WorkflowBundle bundle, String defaultTitle) {
+		try {
+			Statement s = getAnnotation(bundle.getMainWorkflow(),
+					TITLE_ANNOTATION);
+			if (s != null && s.getObject().isLiteral())
+				return s.getObject().asLiteral().getString();
+		} catch (IOException e) {
+			// TODO log this error?
+		}
+		return defaultTitle;
+	}
+
+	/** Get the description of the main workflow in a workflow bundle. */
+	public String getDescription(WorkflowBundle bundle, String defaultDescription) {
+		try {
+			Statement s = getAnnotation(bundle.getMainWorkflow(),
+					DESCRIPTION_ANNOTATION);
+			if (s != null && s.getObject().isLiteral())
+				return s.getObject().asLiteral().getString();
+		} catch (IOException e) {
+			// TODO log this error?
+		}
+		return defaultDescription;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/SystemUtils.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/SystemUtils.java b/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/SystemUtils.java
new file mode 100644
index 0000000..61fecbc
--- /dev/null
+++ b/taverna-component-activity/src/main/java/org/apache/taverna/component/utils/SystemUtils.java
@@ -0,0 +1,118 @@
+package org.apache.taverna.component.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.JAXBElement;
+
+import org.apache.taverna.component.api.ComponentException;
+import org.apache.taverna.component.registry.api.Description;
+
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.platform.execution.api.InvalidWorkflowException;
+import uk.org.taverna.platform.execution.api.WorkflowCompiler;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+
+public class SystemUtils {
+	private static final String T2FLOW_TYPE = "application/vnd.taverna.t2flow+xml";
+	private static final String SCUFL2_TYPE = "application/vnd.taverna.scufl2.workflow-bundle";
+	private ApplicationConfiguration appConfig;
+	private WorkflowBundleIO workflowBundleIO;
+	private List<WorkflowCompiler> compilers;
+
+	public byte[] serializeBundle(WorkflowBundle bundle) throws ComponentException {
+		try {
+			ByteArrayOutputStream dataflowStream = new ByteArrayOutputStream();
+			workflowBundleIO.writeBundle(bundle, dataflowStream, SCUFL2_TYPE);
+			return dataflowStream.toByteArray();
+		} catch (Exception e) {
+			throw new ComponentException(
+					"failed to serialize component implementation", e);
+		}
+	}
+
+	private String determineMediaTypeForFilename(File file) {
+		String[] pieces = file.getName().split("\\.");
+		switch (pieces[pieces.length - 1]) {
+		case "t2flow":
+			return T2FLOW_TYPE;
+		default:
+			return SCUFL2_TYPE;
+		}
+	}
+
+	public void saveBundle(WorkflowBundle bundle, File file) throws Exception {
+		workflowBundleIO.writeBundle(bundle, file,
+				determineMediaTypeForFilename(file));
+	}
+
+	public WorkflowBundle getBundleFromUri(String uri) throws Exception {
+		return workflowBundleIO.readBundle(new URL(uri), null);
+	}
+
+	public WorkflowBundle getBundle(File file) throws Exception {
+		return workflowBundleIO.readBundle(file, null);
+	}
+
+	public static JAXBElement<?> getElement(Description d, String name)
+			throws ComponentException {
+		for (Object o : d.getContent())
+			if (o instanceof JAXBElement) {
+				JAXBElement<?> el = (JAXBElement<?>) o;
+				if (el.getName().getLocalPart().equals(name))
+					return el;
+			}
+		throw new ComponentException("no " + name + " element");
+	}
+
+	public static String getElementString(Description d, String name)
+			throws ComponentException {
+		return getElement(d, name).getValue().toString().trim();
+	}
+
+	public static String getValue(Description d) {
+		StringBuilder sb = new StringBuilder();
+		for (Object o : d.getContent())
+			if (!(o instanceof JAXBElement))
+				sb.append(o);
+		return sb.toString();
+	}
+
+	public File getApplicationHomeDir() {
+		return appConfig.getApplicationHomeDir();
+	}
+
+	public void setAppConfig(ApplicationConfiguration appConfig) {
+		this.appConfig = appConfig;
+	}
+
+	public void setWorkflowBundler(WorkflowBundleIO workflowBundler) {
+		this.workflowBundleIO = workflowBundler;
+	}
+
+	public void setCompilers(List<WorkflowCompiler> compilers) {
+		this.compilers = compilers;
+	}
+
+	public Dataflow compile(WorkflowBundle implementation)
+			throws InvalidWorkflowException {
+		InvalidWorkflowException exn = null;
+		if (compilers != null)
+			for (WorkflowCompiler c : new ArrayList<>(compilers))
+				try {
+					return c.getDataflow(implementation);
+				} catch (InvalidWorkflowException e) {
+					if (exn == null)
+						exn = e;
+					continue;
+				}
+		if (exn != null)
+			throw exn;
+		throw new InvalidWorkflowException("no compiler available");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/resources/EmptyProfile.xml
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/resources/EmptyProfile.xml b/taverna-component-activity/src/main/resources/EmptyProfile.xml
index 2851b83..cc5edd5 100644
--- a/taverna-component-activity/src/main/resources/EmptyProfile.xml
+++ b/taverna-component-activity/src/main/resources/EmptyProfile.xml
@@ -4,7 +4,7 @@
 	xmlns="http://ns.taverna.org.uk/2012/component/profile"
 	xsi:schemaLocation="http://ns.taverna.org.uk/2012/component/profile ComponentProfile.xsd">
 
-	<id>net.sf.taverna.t2.component.profile.empty</id>
+	<id>org.apache.taverna.component.profile.empty</id>
 	<name>Empty profile</name>
 	<description>A basic empty profile that does not allow additional semantic annotation</description>
 	<component>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/resources/META-INF/spring/component-activity-context.xml
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/resources/META-INF/spring/component-activity-context.xml b/taverna-component-activity/src/main/resources/META-INF/spring/component-activity-context.xml
index 4746ede..f1f47a6 100644
--- a/taverna-component-activity/src/main/resources/META-INF/spring/component-activity-context.xml
+++ b/taverna-component-activity/src/main/resources/META-INF/spring/component-activity-context.xml
@@ -7,16 +7,16 @@
                       http://www.springframework.org/schema/osgi/spring-osgi.xsd">
 
 	<bean id="ComponentLocalHealthChecker"
-		class="net.sf.taverna.t2.component.ComponentActivityLocalChecker" />
+		class="org.apache.taverna.component.ComponentActivityLocalChecker" />
 	<bean id="ComponentUpgradeHealthChecker"
-		class="net.sf.taverna.t2.component.ComponentActivityUpgradeChecker">
+		class="org.apache.taverna.component.ComponentActivityUpgradeChecker">
 		<property name="componentUtil" ref="componentUtil" />
 	</bean>
-	<bean id="baseProfileLocator" class="net.sf.taverna.t2.component.profile.BaseProfileLocator">
+	<bean id="baseProfileLocator" class="org.apache.taverna.component.profile.BaseProfileLocator">
 		<property name="appConfig" ref="app-config" />
 	</bean>
 
-	<bean id="componentActivityFactory" class="net.sf.taverna.t2.component.ComponentActivityFactory">
+	<bean id="componentActivityFactory" class="org.apache.taverna.component.ComponentActivityFactory">
 		<property name="componentUtil" ref="componentUtil" />
 		<property name="dataflowCache" ref="cache" />
 		<property name="edits" ref="edits" />
@@ -24,32 +24,32 @@
 	</bean>
 
 	<bean id="networkRegistry"
-		class="net.sf.taverna.t2.component.registry.standard.NewComponentRegistryFactory">
+		class="org.apache.taverna.component.registry.standard.NewComponentRegistryFactory">
 		<property name="credentialManager" ref="credentialManager" />
 		<property name="componentUtil" ref="componentUtil" />
 		<property name="systemUtils" ref="systemUtil" />
 		<property name="annotationUtils" ref="annotationUtil" />
 	</bean>
 	<bean id="fileRegistry"
-		class="net.sf.taverna.t2.component.registry.local.LocalComponentRegistryFactory">
+		class="org.apache.taverna.component.registry.local.LocalComponentRegistryFactory">
 		<property name="componentUtil" ref="componentUtil" />
 		<property name="systemUtils" ref="systemUtil" />
 	</bean>
-	<bean id="componentUtil" class="net.sf.taverna.t2.component.registry.ComponentUtil">
+	<bean id="componentUtil" class="org.apache.taverna.component.registry.ComponentUtil">
 		<property name="networkLocator" ref="networkRegistry" />
 		<property name="fileLocator" ref="fileRegistry" />
 		<property name="baseLocator" ref="baseProfileLocator" />
 	</bean>
 
-	<bean id="cache" class="net.sf.taverna.t2.component.registry.ComponentImplementationCache">
+	<bean id="cache" class="org.apache.taverna.component.registry.ComponentImplementationCache">
 		<property name="componentUtil" ref="componentUtil" />
 	</bean>
-	<bean id="systemUtil" class="net.sf.taverna.t2.component.utils.SystemUtils">
+	<bean id="systemUtil" class="org.apache.taverna.component.utils.SystemUtils">
 		<property name="appConfig" ref="app-config" />
 		<property name="workflowBundler" ref="workflowBundleIO" />
 		<property name="compilers" ref="compilers" />
 	</bean>
-	<bean id="annotationUtil" class="net.sf.taverna.t2.component.utils.AnnotationUtils" />
+	<bean id="annotationUtil" class="org.apache.taverna.component.utils.AnnotationUtils" />
 
 	<osgi:service ref="ComponentLocalHealthChecker"
 		interface="net.sf.taverna.t2.workflowmodel.health.HealthChecker" />
@@ -65,6 +65,6 @@
 	<osgi:reference id="credentialManager"
 		interface="net.sf.taverna.t2.security.credentialmanager.CredentialManager" />
 	<osgi:reference id="edits" interface="net.sf.taverna.t2.workflowmodel.Edits" />
-	<osgi:reference id="workflowBundleIO" interface="uk.org.taverna.scufl2.api.io.WorkflowBundleIO" />
+	<osgi:reference id="workflowBundleIO" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleIO" />
 	<osgi:list id="compilers" interface="uk.org.taverna.platform.execution.api.WorkflowCompiler" />
 </beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/fb982e2f/taverna-component-activity/src/main/resources/NewMyExperimentSchema.xsd
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/resources/NewMyExperimentSchema.xsd b/taverna-component-activity/src/main/resources/NewMyExperimentSchema.xsd
index ba06860..0a8dc83 100644
--- a/taverna-component-activity/src/main/resources/NewMyExperimentSchema.xsd
+++ b/taverna-component-activity/src/main/resources/NewMyExperimentSchema.xsd
@@ -7,7 +7,7 @@
 	<xs:annotation>
 		<xs:appinfo>
 			<jxb:schemaBindings>
-				<jxb:package name="net.sf.taverna.t2.component.registry.api" />
+				<jxb:package name="org.apache.taverna.component.registry.api" />
 			</jxb:schemaBindings>
 		</xs:appinfo>
 	</xs:annotation>