http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java
new file mode 100644
index 0000000..fd0285d
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistry.java
@@ -0,0 +1,220 @@
+package io.github.taverna_extras.component.registry.local;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.apache.commons.io.FileUtils.deleteDirectory;
+import static org.apache.commons.io.FileUtils.writeStringToFile;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.profile.ComponentProfileImpl;
+import io.github.taverna_extras.component.registry.ComponentRegistry;
+import io.github.taverna_extras.component.registry.ComponentUtil;
+import io.github.taverna_extras.component.utils.SystemUtils;
+
+/**
+ * A component registry implemented using the local file system. Note that the
+ * components it contains are <i>not</i> shareable.
+ * 
+ * @author alanrw
+ */
+class LocalComponentRegistry extends ComponentRegistry {
+       private static final Logger logger = 
getLogger(LocalComponentRegistry.class);
+       static final String ENC = "utf-8";
+       private ComponentUtil util;
+       private SystemUtils system;
+       private File baseDir;
+
+       public LocalComponentRegistry(File registryDir, ComponentUtil util,
+                       SystemUtils system) throws ComponentException {
+               super(registryDir);
+               baseDir = registryDir;
+               this.util = util;
+               this.system = system;
+       }
+
+       @Override
+       public Family internalCreateComponentFamily(String name,
+                       Profile componentProfile, String description, License 
license,
+                       SharingPolicy sharingPolicy) throws ComponentException {
+               File newFamilyDir = new File(getComponentFamiliesDir(), name);
+               newFamilyDir.mkdirs();
+               File profileFile = new File(newFamilyDir, "profile");
+               try {
+                       writeStringToFile(profileFile, 
componentProfile.getName(), ENC);
+               } catch (IOException e) {
+                       throw new ComponentException("Could not write out 
profile", e);
+               }
+               File descriptionFile = new File(newFamilyDir, "description");
+               try {
+                       writeStringToFile(descriptionFile, description, ENC);
+               } catch (IOException e) {
+                       throw new ComponentException("Could not write out 
description", e);
+               }
+               return new LocalComponentFamily(this, newFamilyDir, util, 
system);
+       }
+
+       @Override
+       protected void populateFamilyCache() throws ComponentException {
+               File familiesDir = getComponentFamiliesDir();
+               for (File subFile : familiesDir.listFiles()) {
+                       if (!subFile.isDirectory())
+                               continue;
+                       LocalComponentFamily newFamily = new 
LocalComponentFamily(this,
+                                       subFile, util, system);
+                       familyCache.put(newFamily.getName(), newFamily);
+               }
+       }
+
+       @Override
+       protected void populateProfileCache() throws ComponentException {
+               File profilesDir = getComponentProfilesDir();
+               for (File subFile : profilesDir.listFiles())
+                       if (subFile.isFile() && (!subFile.isHidden())
+                                       && subFile.getName().endsWith(".xml"))
+                               try {
+                                       profileCache.add(new 
LocalComponentProfile(subFile));
+                               } catch (MalformedURLException e) {
+                                       logger.error("Unable to read profile", 
e);
+                               }
+       }
+
+       @Override
+       protected void internalRemoveComponentFamily(Family componentFamily)
+                       throws ComponentException {
+               try {
+                       deleteDirectory(new File(getComponentFamiliesDir(),
+                                       componentFamily.getName()));
+               } catch (IOException e) {
+                       throw new ComponentException("Unable to delete 
component family", e);
+               }
+       }
+
+       private File getBaseDir() {
+               baseDir.mkdirs();
+               return baseDir;
+       }
+
+       private File getComponentFamiliesDir() {
+               File componentFamiliesDir = new File(getBaseDir(), 
"componentFamilies");
+               componentFamiliesDir.mkdirs();
+               return componentFamiliesDir;
+       }
+
+       private File getComponentProfilesDir() {
+               File componentProfilesDir = new File(getBaseDir(), 
"componentProfiles");
+               componentProfilesDir.mkdirs();
+               return componentProfilesDir;
+       }
+
+       @Override
+       public Profile internalAddComponentProfile(Profile componentProfile,
+                       License license, SharingPolicy sharingPolicy)
+                       throws ComponentException {
+               String name = componentProfile.getName().replaceAll("\\W+", "")
+                               + ".xml";
+               String inputString = componentProfile.getXML();
+               File outputFile = new File(getComponentProfilesDir(), name);
+               try {
+                       writeStringToFile(outputFile, inputString);
+               } catch (IOException e) {
+                       throw new ComponentException("Unable to save profile", 
e);
+               }
+
+               try {
+                       return new LocalComponentProfile(outputFile);
+               } catch (MalformedURLException e) {
+                       throw new ComponentException("Unable to create 
profile", e);
+               }
+       }
+
+       @Override
+       public int hashCode() {
+               return 31 + ((baseDir == null) ? 0 : baseDir.hashCode());
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               LocalComponentRegistry other = (LocalComponentRegistry) obj;
+               if (baseDir == null)
+                       return (other.baseDir == null);
+               return baseDir.equals(other.baseDir);
+       }
+
+       @Override
+       public void populatePermissionCache() {
+               return;
+       }
+
+       @Override
+       public void populateLicenseCache() {
+               return;
+       }
+
+       @Override
+       public License getPreferredLicense() {
+               return null;
+       }
+
+       @Override
+       public Set<Version.ID> searchForComponents(String prefixString, String 
text)
+                       throws ComponentException {
+               throw new ComponentException("Local registries cannot be 
searched yet");
+       }
+
+       @Override
+       public String getRegistryTypeName() {
+               return "File System";
+       }
+
+       class LocalComponentProfile extends ComponentProfileImpl {
+               URI uri;
+
+               LocalComponentProfile(File file) throws MalformedURLException,
+                               ComponentException {
+                       super(LocalComponentRegistry.this, file.toURI(), util
+                                       .getBaseProfileLocator());
+                       uri = file.toURI();
+               }
+
+               @Override
+               public String toString() {
+                       return "Local Component Profile[" + uri + "]";
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java
new file mode 100644
index 0000000..f2625d1
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentRegistryFactory.java
@@ -0,0 +1,62 @@
+package io.github.taverna_extras.component.registry.local;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.registry.ComponentUtil;
+import io.github.taverna_extras.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java
new file mode 100644
index 0000000..976aa8b
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/local/LocalComponentVersion.java
@@ -0,0 +1,108 @@
+package io.github.taverna_extras.component.registry.local;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.Integer.parseInt;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.registry.local.LocalComponent.COMPONENT_FILENAME;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.registry.ComponentVersion;
+import io.github.taverna_extras.component.utils.SystemUtils;
+
+import org.apache.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java
new file mode 100644
index 0000000..87b99b1
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Client.java
@@ -0,0 +1,654 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.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 
io.github.taverna_extras.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 org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.ComponentException;
+import 
io.github.taverna_extras.component.registry.standard.Client.MyExperimentConnector.ServerResponse;
+import io.github.taverna_extras.component.registry.standard.annotations.Unused;
+import org.apache.taverna.security.credentialmanager.CMException;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+import org.apache.taverna.security.credentialmanager.UsernamePassword;
+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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java
new file mode 100644
index 0000000..44de963
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponent.java
@@ -0,0 +1,239 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.lang.String.format;
+import static 
io.github.taverna_extras.component.registry.standard.NewComponentRegistry.logger;
+import static 
io.github.taverna_extras.component.registry.standard.Policy.getPolicy;
+import static 
io.github.taverna_extras.component.utils.SystemUtils.getElementString;
+import static io.github.taverna_extras.component.utils.SystemUtils.getValue;
+
+import java.lang.ref.SoftReference;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.IllegalFormatException;
+
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.component.api.Registry;
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.registry.Component;
+import io.github.taverna_extras.component.registry.ComponentVersion;
+import io.github.taverna_extras.component.registry.api.ComponentType;
+import io.github.taverna_extras.component.registry.api.Description;
+import io.github.taverna_extras.component.utils.SystemUtils;
+
+import org.apache.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java
new file mode 100644
index 0000000..1c16b1e
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentFamily.java
@@ -0,0 +1,151 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static 
io.github.taverna_extras.component.utils.SystemUtils.getElementString;
+
+import java.util.List;
+
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.registry.ComponentFamily;
+import io.github.taverna_extras.component.registry.ComponentUtil;
+import io.github.taverna_extras.component.registry.api.ComponentFamilyType;
+import io.github.taverna_extras.component.registry.api.Description;
+
+import org.apache.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java
new file mode 100644
index 0000000..5e08b4b
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentLicense.java
@@ -0,0 +1,76 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java
new file mode 100644
index 0000000..372c853
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentProfile.java
@@ -0,0 +1,121 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static 
io.github.taverna_extras.component.utils.SystemUtils.getElementString;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.profile.BaseProfileLocator;
+import io.github.taverna_extras.component.profile.ComponentProfileImpl;
+import io.github.taverna_extras.component.registry.api.ComponentProfileType;
+import io.github.taverna_extras.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java
new file mode 100644
index 0000000..00a549e
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistry.java
@@ -0,0 +1,485 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import static org.apache.log4j.Logger.getLogger;
+import static 
io.github.taverna_extras.component.registry.standard.Policy.PRIVATE;
+import static 
io.github.taverna_extras.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 org.apache.log4j.Logger;
+import io.github.taverna_extras.component.api.Component;
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.api.Family;
+import io.github.taverna_extras.component.api.License;
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.api.Version;
+import io.github.taverna_extras.component.api.Version.ID;
+import io.github.taverna_extras.component.api.profile.Profile;
+import io.github.taverna_extras.component.registry.ComponentRegistry;
+import io.github.taverna_extras.component.registry.ComponentUtil;
+import 
io.github.taverna_extras.component.registry.ComponentVersionIdentification;
+import 
io.github.taverna_extras.component.registry.api.ComponentDescriptionList;
+import io.github.taverna_extras.component.registry.api.ComponentFamilyList;
+import io.github.taverna_extras.component.registry.api.ComponentFamilyType;
+import io.github.taverna_extras.component.registry.api.ComponentProfileList;
+import io.github.taverna_extras.component.registry.api.ComponentProfileType;
+import io.github.taverna_extras.component.registry.api.ComponentType;
+import io.github.taverna_extras.component.registry.api.Content;
+import io.github.taverna_extras.component.registry.api.Description;
+import io.github.taverna_extras.component.registry.api.LicenseList;
+import io.github.taverna_extras.component.registry.api.LicenseType;
+import io.github.taverna_extras.component.registry.api.ObjectFactory;
+import io.github.taverna_extras.component.registry.api.Permissions;
+import io.github.taverna_extras.component.registry.api.PolicyList;
+import io.github.taverna_extras.component.utils.AnnotationUtils;
+import io.github.taverna_extras.component.utils.SystemUtils;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+
+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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java
new file mode 100644
index 0000000..43dc37d
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/NewComponentRegistryFactory.java
@@ -0,0 +1,83 @@
+package io.github.taverna_extras.component.registry.standard;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static 
io.github.taverna_extras.component.registry.standard.NewComponentRegistry.jaxbContext;
+import static 
io.github.taverna_extras.component.registry.standard.NewComponentRegistry.logger;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.github.taverna_extras.component.api.ComponentException;
+import io.github.taverna_extras.component.registry.ComponentRegistry;
+import io.github.taverna_extras.component.registry.ComponentUtil;
+import io.github.taverna_extras.component.utils.AnnotationUtils;
+import io.github.taverna_extras.component.utils.SystemUtils;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java
new file mode 100644
index 0000000..3b521af
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/Policy.java
@@ -0,0 +1,136 @@
+package io.github.taverna_extras.component.registry.standard;
+
+import static java.lang.System.identityHashCode;
+import static 
io.github.taverna_extras.component.registry.api.Privilege.DOWNLOAD;
+import static io.github.taverna_extras.component.registry.api.Privilege.VIEW;
+
+import io.github.taverna_extras.component.api.SharingPolicy;
+import io.github.taverna_extras.component.registry.api.Permissions;
+import io.github.taverna_extras.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/b7b61e71/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java
----------------------------------------------------------------------
diff --git 
a/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java
 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java
new file mode 100644
index 0000000..e6a709b
--- /dev/null
+++ 
b/taverna-component-activity/src/main/java/io/github/taverna_extras/component/registry/standard/annotations/Unused.java
@@ -0,0 +1,43 @@
+package io.github.taverna_extras.component.registry.standard.annotations;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static java.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 {
+
+}


Reply via email to