You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 11:35:18 UTC
[03/58] [abbrv] incubator-taverna-plugin-component git commit:
taverna-component-activity/
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/Component.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/Component.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/Component.java
new file mode 100644
index 0000000..4e8ac52
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/Component.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.component.registry;
+
+import static java.util.Collections.synchronizedSortedMap;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Version;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * A Component is a building block for creating Taverna workflows. Components
+ * and must comply with the ComponentProfile of their ComponentFamily.
+ *
+ * @author David Withers
+ */
+public abstract class Component implements
+ net.sf.taverna.t2.component.api.Component {
+ private String name;
+ private String description;
+ private URL url;
+ /**
+ * Mapping from version numbers to version implementations.
+ */
+ protected SortedMap<Integer, Version> versionMap = new TreeMap<>();
+
+ protected Component(URL url) {
+ this.url = url;
+ }
+
+ protected Component(String url) {
+ try {
+ this.url = new URL(url);
+ } catch (MalformedURLException e) {
+ // nothing
+ }
+ }
+
+ protected Component(File fileDir) {
+ try {
+ this.url = fileDir.toURI().toURL();
+ } catch (MalformedURLException e) {
+ // nothing
+ }
+ }
+
+ @Override
+ public final synchronized String getName() {
+ if (name == null)
+ name = internalGetName();
+ return name;
+ }
+
+ /**
+ * The real implementation of the name fetching. Caching already handled.
+ *
+ * @return The name of the component.
+ */
+ protected abstract String internalGetName();
+
+ @Override
+ public final synchronized String getDescription() {
+ if (description == null)
+ description = internalGetDescription();
+ return description;
+ }
+
+ /**
+ * The real implementation of the description fetching. Caching already
+ * handled.
+ *
+ * @return The description of the component.
+ */
+ protected abstract String internalGetDescription();
+
+ @Override
+ public final SortedMap<Integer, Version> getComponentVersionMap() {
+ synchronized (versionMap) {
+ checkComponentVersionMap();
+ return synchronizedSortedMap(versionMap);
+ }
+ }
+
+ private void checkComponentVersionMap() {
+ if (versionMap.isEmpty())
+ populateComponentVersionMap();
+ }
+
+ /**
+ * Create the contents of the {@link #versionMap} field.
+ */
+ protected abstract void populateComponentVersionMap();
+
+ @Override
+ public final Version getComponentVersion(Integer version)
+ throws ComponentException {
+ synchronized (versionMap) {
+ checkComponentVersionMap();
+ return versionMap.get(version);
+ }
+ }
+
+ @Override
+ public final Version addVersionBasedOn(WorkflowBundle bundle,
+ String revisionComment) throws ComponentException {
+ Version result = internalAddVersionBasedOn(bundle, revisionComment);
+ synchronized (versionMap) {
+ checkComponentVersionMap();
+ versionMap.put(result.getVersionNumber(), result);
+ }
+ return result;
+ }
+
+ /**
+ * Manufacture a new version of a component. Does not add to the overall
+ * version map.
+ *
+ * @param bundle
+ * The definition of the component.
+ * @param revisionComment
+ * The description of the version.
+ * @return The new version of the component.
+ * @throws RegistryException
+ */
+ protected abstract Version internalAddVersionBasedOn(WorkflowBundle bundle,
+ String revisionComment) throws ComponentException;
+
+ @Override
+ public final URL getComponentURL() {
+ return url;
+ }
+
+ @Override
+ public void delete() throws ComponentException {
+ getFamily().removeComponent(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentFamily.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentFamily.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentFamily.java
new file mode 100644
index 0000000..7339b10
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentFamily.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.component.registry;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.taverna.t2.component.api.Component;
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.api.profile.Profile;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * A ComponentFamily is a collection of Components that share the same
+ * ComponentProfile.
+ *
+ * @author David Withers
+ */
+public abstract class ComponentFamily implements
+ net.sf.taverna.t2.component.api.Family {
+ private Registry parentRegistry;
+ private String name;
+ private String description;
+ private Profile componentProfile;
+ private ComponentUtil util;
+
+ protected Map<String, Component> componentCache = new HashMap<>();
+
+ public ComponentFamily(Registry componentRegistry, ComponentUtil util) {
+ this.parentRegistry = componentRegistry;
+ this.util = util;
+ }
+
+ @Override
+ public Registry getComponentRegistry() {
+ return parentRegistry;
+ }
+
+ @Override
+ public final synchronized String getName() {
+ if (name == null) {
+ name = internalGetName();
+ }
+ return name;
+ }
+
+ protected abstract String internalGetName();
+
+ @Override
+ public final synchronized String getDescription() {
+ if (description == null) {
+ description = internalGetDescription();
+ }
+ return description;
+ }
+
+ protected abstract String internalGetDescription();
+
+ @Override
+ public final synchronized Profile getComponentProfile()
+ throws ComponentException {
+ if (componentProfile == null)
+ componentProfile = internalGetComponentProfile();
+ if (componentProfile == null) {
+ Profile baseProfile = util.getBaseProfile();
+ if (baseProfile != null) {
+ return baseProfile;
+ }
+ }
+ return componentProfile;
+ }
+
+ protected abstract Profile internalGetComponentProfile()
+ throws ComponentException;
+
+ @Override
+ public final List<Component> getComponents() throws ComponentException {
+ checkComponentCache();
+ return new ArrayList<>(componentCache.values());
+ }
+
+ private void checkComponentCache() throws ComponentException {
+ synchronized (componentCache) {
+ if (componentCache.isEmpty())
+ populateComponentCache();
+ }
+ }
+
+ protected abstract void populateComponentCache() throws ComponentException;
+
+ @Override
+ public final Component getComponent(String componentName)
+ throws ComponentException {
+ checkComponentCache();
+ return componentCache.get(componentName);
+ }
+
+ @Override
+ public final Version createComponentBasedOn(String componentName,
+ String description, WorkflowBundle bundle) throws ComponentException {
+ if (componentName == null)
+ throw new ComponentException("Component name must not be null");
+ if (bundle == null)
+ throw new ComponentException("workflow must not be null");
+ checkComponentCache();
+ if (componentCache.containsKey(componentName))
+ throw new ComponentException("Component name already used");
+ Version version = internalCreateComponentBasedOn(componentName,
+ description, bundle);
+ synchronized (componentCache) {
+ Component c = version.getComponent();
+ componentCache.put(componentName, c);
+ }
+ return version;
+ }
+
+ protected abstract Version internalCreateComponentBasedOn(
+ String componentName, String description, WorkflowBundle bundle)
+ throws ComponentException;
+
+ @Override
+ public final void removeComponent(Component component)
+ throws ComponentException {
+ if (component != null) {
+ checkComponentCache();
+ synchronized (componentCache) {
+ componentCache.remove(component.getName());
+ }
+ internalRemoveComponent(component);
+ }
+ }
+
+ protected abstract void internalRemoveComponent(Component component)
+ throws ComponentException;
+
+ @Override
+ public void delete() throws ComponentException {
+ getComponentRegistry().removeComponentFamily(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentImplementationCache.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentImplementationCache.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentImplementationCache.java
new file mode 100644
index 0000000..2283295
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentImplementationCache.java
@@ -0,0 +1,65 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry;
+
+import static java.lang.System.currentTimeMillis;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Version;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ComponentImplementationCache {
+ private class Entry {
+ WorkflowBundle implementation;
+ long timestamp;
+ }
+ private final long VALIDITY = 15 * 60 * 1000;
+ private final Logger logger = getLogger(ComponentImplementationCache.class);
+ private final Map<Version.ID, Entry> cache = new WeakHashMap<>();
+ private ComponentUtil utils;
+
+ public void setComponentUtil(ComponentUtil utils) {
+ this.utils = utils;
+ }
+
+ public WorkflowBundle getImplementation(Version.ID id) throws ComponentException {
+ long now = currentTimeMillis();
+ synchronized (id) {
+ Entry entry = cache.get(id);
+ if (entry != null && entry.timestamp >= now)
+ return entry.implementation;
+ logger.info("before calculate component version for " + id);
+ Version componentVersion;
+ try {
+ componentVersion = utils.getVersion(id);
+ } catch (RuntimeException e) {
+ if (entry != null)
+ return entry.implementation;
+ throw new ComponentException(e.getMessage(), e);
+ }
+ logger.info("calculated component version for " + id + " as "
+ + componentVersion.getVersionNumber() + "; retrieving dataflow");
+ WorkflowBundle implementation = componentVersion.getImplementation();
+ //DataflowValidationReport report = implementation.checkValidity();
+ //logger.info("component version " + id + " incomplete:"
+ // + report.isWorkflowIncomplete() + " valid:"
+ // + report.isValid());
+ entry = new Entry();
+ entry.implementation = implementation;
+ entry.timestamp = now + VALIDITY;
+ return cache.put(id, entry).implementation;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentRegistry.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentRegistry.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentRegistry.java
new file mode 100644
index 0000000..40d1346
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentRegistry.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.component.registry;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.License;
+import net.sf.taverna.t2.component.api.SharingPolicy;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.api.profile.Profile;
+
+/**
+ * A ComponentRegistry contains ComponentFamilies and ComponentProfiles.
+ *
+ * @author David Withers
+ */
+public abstract class ComponentRegistry implements
+ net.sf.taverna.t2.component.api.Registry {
+ protected Map<String, Family> familyCache = new HashMap<>();
+ protected List<Profile> profileCache = new ArrayList<>();
+ protected List<SharingPolicy> permissionCache = new ArrayList<>();
+ protected List<License> licenseCache = new ArrayList<>();
+
+ private URL registryBase;
+
+ protected ComponentRegistry(URL registryBase) throws ComponentException {
+ this.registryBase = registryBase;
+ }
+
+ protected ComponentRegistry(File fileDir) throws ComponentException {
+ try {
+ this.registryBase = fileDir.toURI().toURL();
+ } catch (MalformedURLException e) {
+ throw new ComponentException(e);
+ }
+ }
+
+ @Override
+ public final List<Family> getComponentFamilies() throws ComponentException {
+ checkFamilyCache();
+ return new ArrayList<Family>(familyCache.values());
+ }
+
+ private void checkFamilyCache() throws ComponentException {
+ synchronized (familyCache) {
+ if (familyCache.isEmpty())
+ populateFamilyCache();
+ }
+ }
+
+ protected abstract void populateFamilyCache() throws ComponentException;
+
+ @Override
+ public final Family getComponentFamily(String familyName)
+ throws ComponentException {
+ checkFamilyCache();
+ return familyCache.get(familyName);
+ }
+
+ @Override
+ public final Family createComponentFamily(String familyName,
+ Profile componentProfile, String description, License license,
+ SharingPolicy sharingPolicy) throws ComponentException {
+ if (familyName == null)
+ throw new ComponentException(
+ "Component family name must not be null");
+ if (componentProfile == null)
+ throw new ComponentException("Component profile must not be null");
+ if (getComponentFamily(familyName) != null)
+ throw new ComponentException("Component family already exists");
+
+ Family result = internalCreateComponentFamily(familyName,
+ componentProfile, description, license, sharingPolicy);
+ checkFamilyCache();
+ synchronized (familyCache) {
+ familyCache.put(familyName, result);
+ }
+ return result;
+ }
+
+ protected abstract Family internalCreateComponentFamily(String familyName,
+ Profile componentProfile, String description, License license,
+ SharingPolicy sharingPolicy) throws ComponentException;
+
+ @Override
+ public final void removeComponentFamily(Family componentFamily)
+ throws ComponentException {
+ if (componentFamily != null) {
+ checkFamilyCache();
+ synchronized (familyCache) {
+ familyCache.remove(componentFamily.getName());
+ }
+ internalRemoveComponentFamily(componentFamily);
+ }
+ }
+
+ protected abstract void internalRemoveComponentFamily(Family componentFamily)
+ throws ComponentException;
+
+ @Override
+ public final URL getRegistryBase() {
+ return registryBase;
+ }
+
+ @Override
+ public final String getRegistryBaseString() {
+ String urlString = getRegistryBase().toString();
+ if (urlString.endsWith("/"))
+ urlString = urlString.substring(0, urlString.length() - 1);
+ return urlString;
+ }
+
+ private void checkProfileCache() throws ComponentException {
+ synchronized (profileCache) {
+ if (profileCache.isEmpty())
+ populateProfileCache();
+ }
+ }
+
+ protected abstract void populateProfileCache() throws ComponentException;
+
+ @Override
+ public final List<Profile> getComponentProfiles() throws ComponentException {
+ checkProfileCache();
+ return profileCache;
+ }
+
+ @Override
+ public final Profile getComponentProfile(String id)
+ throws ComponentException {
+ // TODO use a map instead of a *linear search*...
+ for (Profile p : getComponentProfiles())
+ if (p.getId().equals(id))
+ return p;
+ return null;
+ }
+
+ @Override
+ public final Profile addComponentProfile(Profile componentProfile,
+ License license, SharingPolicy sharingPolicy)
+ throws ComponentException {
+ if (componentProfile == null) {
+ throw new ComponentException("componentProfile is null");
+ }
+ Profile result = null;
+ checkProfileCache();
+ for (Profile p : getComponentProfiles())
+ if (p.getId().equals(componentProfile.getId())) {
+ result = p;
+ break;
+ }
+
+ if (result == null) {
+ result = internalAddComponentProfile(componentProfile, license,
+ sharingPolicy);
+ synchronized (profileCache) {
+ profileCache.add(result);
+ }
+ }
+ return result;
+ }
+
+ protected abstract Profile internalAddComponentProfile(
+ Profile componentProfile, License license,
+ SharingPolicy sharingPolicy) throws ComponentException;
+
+ private void checkPermissionCache() {
+ synchronized (permissionCache) {
+ if (permissionCache.isEmpty())
+ populatePermissionCache();
+ }
+ }
+
+ protected abstract void populatePermissionCache();
+
+ @Override
+ public final List<SharingPolicy> getPermissions() throws ComponentException {
+ checkPermissionCache();
+ return permissionCache;
+ }
+
+ private void checkLicenseCache() {
+ synchronized (licenseCache) {
+ if (licenseCache.isEmpty())
+ populateLicenseCache();
+ }
+ }
+
+ protected abstract void populateLicenseCache();
+
+ @Override
+ public final List<License> getLicenses() throws ComponentException {
+ checkLicenseCache();
+ return licenseCache;
+ }
+
+ protected License getLicenseByAbbreviation(String licenseString)
+ throws ComponentException {
+ checkLicenseCache();
+ for (License l : getLicenses())
+ if (l.getAbbreviation().equals(licenseString))
+ return l;
+ return null;
+ }
+
+ @Override
+ public abstract License getPreferredLicense() throws ComponentException;
+
+ @Override
+ public abstract Set<Version.ID> searchForComponents(String prefixString,
+ String text) throws ComponentException;
+
+ @Override
+ public String toString() {
+ String[] names = getClass().getName().split("\\.");
+ return names[names.length-1] + ": " + registryBase;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentUtil.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentUtil.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentUtil.java
new file mode 100644
index 0000000..4380d22
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentUtil.java
@@ -0,0 +1,113 @@
+package net.sf.taverna.t2.component.registry;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.taverna.t2.component.api.Component;
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.ComponentFactory;
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.profile.Profile;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.profile.BaseProfileLocator;
+import net.sf.taverna.t2.component.profile.ComponentProfileImpl;
+import net.sf.taverna.t2.component.registry.local.LocalComponentRegistryFactory;
+import net.sf.taverna.t2.component.registry.standard.NewComponentRegistryFactory;
+
+import org.springframework.beans.factory.annotation.Required;
+
+/**
+ * @author alanrw
+ * @author dkf
+ */
+public class ComponentUtil implements ComponentFactory {
+ private NewComponentRegistryFactory netLocator;
+ private BaseProfileLocator base;
+ private LocalComponentRegistryFactory fileLocator;
+
+ private final Map<String, Registry> cache = new HashMap<>();
+
+ @Required
+ public void setNetworkLocator(NewComponentRegistryFactory locator) {
+ this.netLocator = locator;
+ }
+
+ @Required
+ public void setFileLocator(LocalComponentRegistryFactory fileLocator) {
+ this.fileLocator = fileLocator;
+ }
+
+ @Required
+ public void setBaseLocator(BaseProfileLocator base) {
+ this.base = base;
+ }
+
+ @Override
+ public Registry getRegistry(URL registryBase) throws ComponentException {
+ Registry registry = cache.get(registryBase.toString());
+ if (registry != null)
+ return registry;
+
+ if (registryBase.getProtocol().startsWith("http")) {
+ if (!netLocator.verifyBase(registryBase))
+ throw new ComponentException(
+ "Unable to establish credentials for " + registryBase);
+ registry = netLocator.getComponentRegistry(registryBase);
+ } else
+ registry = fileLocator.getComponentRegistry(registryBase);
+ cache.put(registryBase.toString(), registry);
+ return registry;
+ }
+
+ @Override
+ public Family getFamily(URL registryBase, String familyName)
+ throws ComponentException {
+ return getRegistry(registryBase).getComponentFamily(familyName);
+ }
+
+ @Override
+ public Component getComponent(URL registryBase, String familyName,
+ String componentName) throws ComponentException {
+ return getRegistry(registryBase).getComponentFamily(familyName)
+ .getComponent(componentName);
+ }
+
+ @Override
+ public Version getVersion(URL registryBase, String familyName,
+ String componentName, Integer componentVersion)
+ throws ComponentException {
+ return getRegistry(registryBase).getComponentFamily(familyName)
+ .getComponent(componentName)
+ .getComponentVersion(componentVersion);
+ }
+
+ @Override
+ public Version getVersion(Version.ID ident) throws ComponentException {
+ return getVersion(ident.getRegistryBase(), ident.getFamilyName(),
+ ident.getComponentName(), ident.getComponentVersion());
+ }
+
+ @Override
+ public Component getComponent(Version.ID ident) throws ComponentException {
+ return getComponent(ident.getRegistryBase(), ident.getFamilyName(),
+ ident.getComponentName());
+ }
+
+ @Override
+ public Profile getProfile(URL url) throws ComponentException {
+ Profile p = new ComponentProfileImpl(url, base);
+ p.getProfileDocument(); // force immediate loading
+ return p;
+ }
+
+ @Override
+ public Profile getBaseProfile() throws ComponentException {
+ return base.getProfile();
+ }
+
+ public BaseProfileLocator getBaseProfileLocator() {
+ return base;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersion.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersion.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersion.java
new file mode 100644
index 0000000..8d6c443
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersion.java
@@ -0,0 +1,65 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry;
+
+import net.sf.taverna.t2.component.api.Component;
+import net.sf.taverna.t2.component.api.ComponentException;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ *
+ */
+public abstract class ComponentVersion implements
+ net.sf.taverna.t2.component.api.Version {
+ private Integer versionNumber;
+ private String description;
+ private Component component;
+
+ protected ComponentVersion(Component component) {
+ this.component = component;
+ }
+
+ @Override
+ public final synchronized Integer getVersionNumber() {
+ if (versionNumber == null)
+ versionNumber = internalGetVersionNumber();
+ return versionNumber;
+ }
+
+ protected abstract Integer internalGetVersionNumber();
+
+ @Override
+ public final synchronized String getDescription() {
+ if (description == null)
+ description = internalGetDescription();
+
+ return description;
+ }
+
+ protected abstract String internalGetDescription();
+
+ @Override
+ public final synchronized WorkflowBundle getImplementation()
+ throws ComponentException {
+ // Cached in dataflow cache
+ return internalGetImplementation();
+ }
+
+ protected abstract WorkflowBundle internalGetImplementation()
+ throws ComponentException;
+
+ @Override
+ public final Component getComponent() {
+ return component;
+ }
+
+ @Override
+ public ID getID() {
+ Component c = getComponent();
+ return new ComponentVersionIdentification(c.getRegistry()
+ .getRegistryBase(), c.getFamily().getName(), c.getName(),
+ getVersionNumber());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersionIdentification.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersionIdentification.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersionIdentification.java
new file mode 100644
index 0000000..9115a32
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/ComponentVersionIdentification.java
@@ -0,0 +1,196 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry;
+
+import java.net.URL;
+
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.api.Version.ID;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ComponentVersionIdentification implements
+ net.sf.taverna.t2.component.api.Version.ID {
+ private static final long serialVersionUID = 1768548650702925916L;
+ private URL registryBase;
+ private String familyName;
+ private String componentName;
+ private Integer componentVersion;
+
+ public ComponentVersionIdentification(URL registryBase, String familyName,
+ String componentName, Integer componentVersion) {
+ super();
+ this.registryBase = registryBase;
+ this.familyName = familyName;
+ this.componentName = componentName;
+ this.componentVersion = componentVersion;
+ }
+
+ public ComponentVersionIdentification(Registry registry, Family family,
+ net.sf.taverna.t2.component.api.Component component, Integer version) {
+ this(registry.getRegistryBase(), family.getName(), component.getName(), version);
+ }
+
+ public ComponentVersionIdentification(Version.ID toBeCopied) {
+ this.registryBase = toBeCopied.getRegistryBase();
+ this.familyName = toBeCopied.getFamilyName();
+ this.componentName = toBeCopied.getComponentName();
+ this.componentVersion = toBeCopied.getComponentVersion();
+ }
+
+ /**
+ * @return the registryBase
+ */
+ @Override
+ public URL getRegistryBase() {
+ return registryBase;
+ }
+
+ /**
+ * @return the familyName
+ */
+ @Override
+ public String getFamilyName() {
+ return familyName;
+ }
+
+ /**
+ * @return the componentName
+ */
+ @Override
+ public String getComponentName() {
+ return componentName;
+ }
+
+ /**
+ * @return the componentVersion
+ */
+ @Override
+ public Integer getComponentVersion() {
+ return componentVersion;
+ }
+
+ /**
+ * @param componentVersion
+ * the componentVersion to set
+ */
+ public void setComponentVersion(Integer componentVersion) {
+ this.componentVersion = componentVersion;
+ }
+
+ /**
+ * @param registryBase
+ * the registryBase to set
+ */
+ public void setRegistryBase(URL registryBase) {
+ this.registryBase = registryBase;
+ }
+
+ /**
+ * @param familyName
+ * the familyName to set
+ */
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ /**
+ * @param componentName
+ * the componentName to set
+ */
+ public void setComponentName(String componentName) {
+ this.componentName = componentName;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((componentName == null) ? 0 : componentName.hashCode());
+ result = prime
+ * result
+ + ((componentVersion == null) ? 0 : componentVersion.hashCode());
+ result = prime * result
+ + ((familyName == null) ? 0 : familyName.hashCode());
+ result = prime * result
+ + ((registryBase == null) ? 0 : registryBase.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ComponentVersionIdentification other = (ComponentVersionIdentification) obj;
+ if (componentName == null) {
+ if (other.componentName != null)
+ return false;
+ } else if (!componentName.equals(other.componentName))
+ return false;
+ if (componentVersion == null) {
+ if (other.componentVersion != null)
+ return false;
+ } else if (!componentVersion.equals(other.componentVersion))
+ return false;
+ if (familyName == null) {
+ if (other.familyName != null)
+ return false;
+ } else if (!familyName.equals(other.familyName))
+ return false;
+ if (registryBase == null) {
+ if (other.registryBase != null)
+ return false;
+ } else if (!registryBase.toString().equals(other.registryBase.toString()))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return getComponentName() + " V. " + getComponentVersion()
+ + " in family " + getFamilyName() + " on "
+ + getRegistryBase().toExternalForm();
+ }
+
+ @Override
+ public boolean mostlyEqualTo(ID id) {
+ if (this == id)
+ return true;
+ if (id == null)
+ return false;
+ if (getClass() != id.getClass())
+ return false;
+ ComponentVersionIdentification other = (ComponentVersionIdentification) id;
+ if (componentName == null) {
+ if (other.componentName != null)
+ return false;
+ } else if (!componentName.equals(other.componentName))
+ return false;
+ if (familyName == null) {
+ if (other.familyName != null)
+ return false;
+ } else if (!familyName.equals(other.familyName))
+ return false;
+ if (registryBase == null) {
+ if (other.registryBase != null)
+ return false;
+ } else if (!registryBase.toString().equals(other.registryBase.toString()))
+ return false;
+ return true;
+ }
+
+ @Override
+ public boolean mostlyEqualTo(net.sf.taverna.t2.component.api.Component c) {
+ return mostlyEqualTo(new ComponentVersionIdentification(c.getRegistry(), c.getFamily(), c, 0));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponent.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponent.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponent.java
new file mode 100644
index 0000000..bfb1007
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponent.java
@@ -0,0 +1,134 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry.local;
+
+import static net.sf.taverna.t2.component.registry.local.LocalComponentRegistry.ENC;
+import static org.apache.commons.io.FileUtils.readFileToString;
+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.util.NoSuchElementException;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.registry.Component;
+import net.sf.taverna.t2.component.utils.SystemUtils;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ *
+ */
+class LocalComponent extends Component {
+ static final String COMPONENT_FILENAME = "dataflow.t2flow";
+ private final File componentDir;
+ private final LocalComponentRegistry registry;
+ private final LocalComponentFamily family;
+ private static Logger logger = getLogger(LocalComponent.class);
+ private SystemUtils system;
+
+ public LocalComponent(File componentDir, LocalComponentRegistry registry,
+ LocalComponentFamily family, SystemUtils system) {
+ super(componentDir);
+ this.system = system;
+ this.componentDir = componentDir;
+ this.registry = registry;
+ this.family = family;
+ }
+
+ @Override
+ protected final Version internalAddVersionBasedOn(WorkflowBundle bundle,
+ String revisionComment) throws ComponentException {
+ Integer nextVersionNumber = 1;
+ try {
+ nextVersionNumber = getComponentVersionMap().lastKey() + 1;
+ } catch (NoSuchElementException e) {
+ // This is OK
+ }
+ File newVersionDir = new File(componentDir,
+ nextVersionNumber.toString());
+ newVersionDir.mkdirs();
+ LocalComponentVersion newComponentVersion = new LocalComponentVersion(
+ this, newVersionDir, system);
+ try {
+ system.saveBundle(bundle, new File(newVersionDir,
+ COMPONENT_FILENAME));
+ } catch (Exception e) {
+ throw new ComponentException("Unable to save component version", e);
+ }
+ File revisionCommentFile = new File(newVersionDir, "description");
+ try {
+ writeStringToFile(revisionCommentFile, revisionComment, ENC);
+ } catch (IOException e) {
+ throw new ComponentException("Could not write out description", e);
+ }
+
+ return newComponentVersion;
+ }
+
+ @Override
+ protected final String internalGetName() {
+ return componentDir.getName();
+ }
+
+ @Override
+ protected final void populateComponentVersionMap() {
+ for (File subFile : componentDir.listFiles())
+ try {
+ if (subFile.isDirectory())
+ versionMap.put(Integer.valueOf(subFile.getName()),
+ new LocalComponentVersion(this, subFile, system));
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 + ((componentDir == null) ? 0 : componentDir.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LocalComponent other = (LocalComponent) obj;
+ if (componentDir == null)
+ return (other.componentDir == null);
+ return componentDir.equals(other.componentDir);
+ }
+
+ @Override
+ protected final String internalGetDescription() {
+ File descriptionFile = new File(componentDir, "description");
+ try {
+ if (descriptionFile.isFile())
+ return readFileToString(descriptionFile);
+ } catch (IOException e) {
+ logger.error("failed to get description from " + descriptionFile, e);
+ }
+ return "";
+ }
+
+ @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/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentFamily.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentFamily.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentFamily.java
new file mode 100644
index 0000000..96a32ab
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentFamily.java
@@ -0,0 +1,141 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry.local;
+
+import static net.sf.taverna.t2.component.registry.local.LocalComponentRegistry.ENC;
+import static org.apache.commons.io.FileUtils.deleteDirectory;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.commons.io.FileUtils.writeStringToFile;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.sf.taverna.t2.component.api.Component;
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.api.profile.Profile;
+import net.sf.taverna.t2.component.registry.ComponentFamily;
+import net.sf.taverna.t2.component.registry.ComponentUtil;
+import net.sf.taverna.t2.component.utils.SystemUtils;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ *
+ */
+class LocalComponentFamily extends ComponentFamily {
+ private static Logger logger = getLogger(LocalComponentFamily.class);
+ private static final String PROFILE = "profile";
+
+ private final File componentFamilyDir;
+ private SystemUtils system;
+
+ public LocalComponentFamily(LocalComponentRegistry parentRegistry,
+ File componentFamilyDir, ComponentUtil util, SystemUtils system) {
+ super(parentRegistry, util);
+ this.componentFamilyDir = componentFamilyDir;
+ this.system = system;
+ }
+
+ @Override
+ protected final Profile internalGetComponentProfile()
+ throws ComponentException {
+ LocalComponentRegistry parentRegistry = (LocalComponentRegistry) getComponentRegistry();
+ File profileFile = new File(componentFamilyDir, PROFILE);
+ String profileName;
+ try {
+ profileName = readFileToString(profileFile, ENC);
+ } catch (IOException e) {
+ throw new ComponentException("Unable to read profile name", e);
+ }
+ for (Profile p : parentRegistry.getComponentProfiles())
+ if (p.getName().equals(profileName))
+ return p;
+ return null;
+ }
+
+ @Override
+ protected void populateComponentCache() throws ComponentException {
+ for (File subFile : componentFamilyDir.listFiles()) {
+ if (!subFile.isDirectory())
+ continue;
+ LocalComponent newComponent = new LocalComponent(subFile,
+ (LocalComponentRegistry) getComponentRegistry(), this,
+ system);
+ componentCache.put(newComponent.getName(), newComponent);
+ }
+ }
+
+ @Override
+ protected final String internalGetName() {
+ return componentFamilyDir.getName();
+ }
+
+ @Override
+ protected final Version internalCreateComponentBasedOn(
+ String componentName, String description, WorkflowBundle bundle)
+ throws ComponentException {
+ File newSubFile = new File(componentFamilyDir, componentName);
+ if (newSubFile.exists())
+ throw new ComponentException("Component already exists");
+ newSubFile.mkdirs();
+ File descriptionFile = new File(newSubFile, "description");
+ try {
+ writeStringToFile(descriptionFile, description, ENC);
+ } catch (IOException e) {
+ throw new ComponentException("Could not write out description", e);
+ }
+ LocalComponent newComponent = new LocalComponent(newSubFile,
+ (LocalComponentRegistry) getComponentRegistry(), this, system);
+
+ return newComponent.addVersionBasedOn(bundle, "Initial version");
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 + ((componentFamilyDir == null) ? 0 : componentFamilyDir
+ .hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LocalComponentFamily other = (LocalComponentFamily) obj;
+ if (componentFamilyDir == null)
+ return (other.componentFamilyDir == null);
+ return componentFamilyDir.equals(other.componentFamilyDir);
+ }
+
+ @Override
+ protected final String internalGetDescription() {
+ File descriptionFile = new File(componentFamilyDir, "description");
+ try {
+ if (descriptionFile.isFile())
+ return readFileToString(descriptionFile);
+ } catch (IOException e) {
+ logger.error("failed to get description from " + descriptionFile, e);
+ }
+ return "";
+ }
+
+ @Override
+ protected final void internalRemoveComponent(Component component)
+ throws ComponentException {
+ File componentDir = new File(componentFamilyDir, component.getName());
+ try {
+ deleteDirectory(componentDir);
+ } catch (IOException e) {
+ throw new ComponentException("Unable to delete component", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistry.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistry.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistry.java
new file mode 100644
index 0000000..9fcc19a
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistry.java
@@ -0,0 +1,205 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry.local;
+
+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 net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.License;
+import net.sf.taverna.t2.component.api.SharingPolicy;
+import net.sf.taverna.t2.component.api.Version;
+import net.sf.taverna.t2.component.api.profile.Profile;
+import net.sf.taverna.t2.component.profile.ComponentProfileImpl;
+import net.sf.taverna.t2.component.registry.ComponentRegistry;
+import net.sf.taverna.t2.component.registry.ComponentUtil;
+import net.sf.taverna.t2.component.utils.SystemUtils;
+
+import org.apache.log4j.Logger;
+
+/**
+ * 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/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistryFactory.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistryFactory.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistryFactory.java
new file mode 100644
index 0000000..c56fe52
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentRegistryFactory.java
@@ -0,0 +1,45 @@
+package net.sf.taverna.t2.component.registry.local;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.registry.ComponentUtil;
+import net.sf.taverna.t2.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/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentVersion.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentVersion.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentVersion.java
new file mode 100644
index 0000000..74a7389
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/local/LocalComponentVersion.java
@@ -0,0 +1,94 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.component.registry.local;
+
+import static java.lang.Integer.parseInt;
+import static net.sf.taverna.t2.component.registry.local.LocalComponent.COMPONENT_FILENAME;
+import static org.apache.commons.io.FileUtils.readFileToString;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.registry.ComponentVersion;
+import net.sf.taverna.t2.component.utils.SystemUtils;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ *
+ */
+class LocalComponentVersion extends ComponentVersion {
+ private static Logger logger = getLogger(LocalComponentVersion.class);
+
+ private final File componentVersionDir;
+ private SystemUtils system;
+
+ protected LocalComponentVersion(LocalComponent component,
+ File componentVersionDir, SystemUtils system) {
+ super(component);
+ this.componentVersionDir = componentVersionDir;
+ this.system = system;
+ }
+
+ @Override
+ protected final String internalGetDescription() {
+ File descriptionFile = new File(componentVersionDir, "description");
+ try {
+ if (descriptionFile.isFile())
+ return readFileToString(descriptionFile);
+ } catch (IOException e) {
+ logger.error("failed to get description from " + descriptionFile, e);
+ }
+ return "";
+ }
+
+ @Override
+ protected final Integer internalGetVersionNumber() {
+ return parseInt(componentVersionDir.getName());
+ }
+
+ @Override
+ protected final WorkflowBundle internalGetImplementation()
+ throws ComponentException {
+ File filename = new File(componentVersionDir, COMPONENT_FILENAME);
+ try {
+ return system.getBundle(filename);
+ } catch (Exception e) {
+ logger.error(
+ "failed to get component realization from " + filename, e);
+ throw new ComponentException("Unable to open dataflow", e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 + ((componentVersionDir == null) ? 0 : componentVersionDir
+ .hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LocalComponentVersion other = (LocalComponentVersion) obj;
+ if (componentVersionDir == null)
+ return (other.componentVersionDir == null);
+ return componentVersionDir.equals(other.componentVersionDir);
+ }
+
+ @Override
+ public URL getHelpURL() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-component/blob/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/Client.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/Client.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/Client.java
new file mode 100644
index 0000000..61f9997
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/Client.java
@@ -0,0 +1,637 @@
+package net.sf.taverna.t2.component.registry.standard;
+
+import static java.lang.Math.min;
+import static java.lang.String.format;
+import static java.lang.System.getProperty;
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.URLEncoder.encode;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static net.sf.taverna.t2.component.registry.ClientVersion.VERSION;
+import static org.apache.commons.io.IOUtils.copy;
+import static org.apache.log4j.Logger.getLogger;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.registry.standard.Client.MyExperimentConnector.ServerResponse;
+import net.sf.taverna.t2.component.registry.standard.annotations.Unused;
+import net.sf.taverna.t2.security.credentialmanager.CMException;
+import net.sf.taverna.t2.security.credentialmanager.CredentialManager;
+import net.sf.taverna.t2.security.credentialmanager.UsernamePassword;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.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/e15f9c85/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/NewComponent.java
----------------------------------------------------------------------
diff --git a/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/NewComponent.java b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/NewComponent.java
new file mode 100644
index 0000000..a3f9536
--- /dev/null
+++ b/taverna-component-activity/src/main/java/net/sf/taverna/t2/component/registry/standard/NewComponent.java
@@ -0,0 +1,220 @@
+package net.sf.taverna.t2.component.registry.standard;
+
+import static java.lang.String.format;
+import static net.sf.taverna.t2.component.registry.standard.NewComponentRegistry.logger;
+import static net.sf.taverna.t2.component.registry.standard.Policy.getPolicy;
+import static net.sf.taverna.t2.component.utils.SystemUtils.getElementString;
+import static net.sf.taverna.t2.component.utils.SystemUtils.getValue;
+
+import java.lang.ref.SoftReference;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.IllegalFormatException;
+
+import net.sf.taverna.t2.component.api.ComponentException;
+import net.sf.taverna.t2.component.api.Family;
+import net.sf.taverna.t2.component.api.License;
+import net.sf.taverna.t2.component.api.Registry;
+import net.sf.taverna.t2.component.api.SharingPolicy;
+import net.sf.taverna.t2.component.registry.Component;
+import net.sf.taverna.t2.component.registry.ComponentVersion;
+import net.sf.taverna.t2.component.registry.api.ComponentType;
+import net.sf.taverna.t2.component.registry.api.Description;
+import net.sf.taverna.t2.component.utils.SystemUtils;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+class NewComponent extends Component {
+ static final String ELEMENTS = "title,description";
+ static final String EXTRA = "license-type,permissions";
+
+ private final SystemUtils system;
+ final NewComponentRegistry registry;
+ final NewComponentFamily family;
+ private final String id;
+ private final String title;
+ private final String description;
+ private final String resource;
+
+ NewComponent(NewComponentRegistry registry, NewComponentFamily family,
+ Description cd, SystemUtils system) throws ComponentException {
+ super(cd.getUri());
+ this.system = system;
+ this.registry = registry;
+ this.family = family;
+ id = cd.getId().trim();
+ title = getElementString(cd, "title");
+ description = getElementString(cd, "description");
+ resource = cd.getResource();
+ }
+
+ NewComponent(NewComponentRegistry registry, NewComponentFamily family,
+ ComponentType ct, SystemUtils system) {
+ super(ct.getUri());
+ this.system = system;
+ this.registry = registry;
+ this.family = family;
+ id = ct.getId().trim();
+ title = ct.getTitle().trim();
+ description = ct.getDescription().trim();
+ resource = ct.getResource();
+ }
+
+ public ComponentType getCurrent(String elements) throws ComponentException {
+ return registry.getComponentById(id, null, elements);
+ }
+
+ @Override
+ protected String internalGetName() {
+ return title;
+ }
+
+ @Override
+ protected String internalGetDescription() {
+ return description;
+ }
+
+ @Override
+ protected void populateComponentVersionMap() {
+ try {
+ for (Description d : getCurrent("versions").getVersions()
+ .getWorkflow())
+ versionMap.put(d.getVersion(), new Version(d.getVersion(),
+ getValue(d)));
+ } catch (ComponentException e) {
+ logger.warn("failed to retrieve version list: " + e.getMessage());
+ }
+ }
+
+ @Override
+ protected Version internalAddVersionBasedOn(WorkflowBundle bundle,
+ String revisionComment) throws ComponentException {
+ /*
+ * Only fetch the license and sharing policy now; user might have
+ * updated them on the site and we want to duplicate.
+ */
+ ComponentType ct = getCurrent(EXTRA);
+ License license = registry.getLicense(getValue(ct.getLicenseType())
+ .trim());
+ SharingPolicy sharingPolicy = getPolicy(ct.getPermissions());
+
+ return (Version) registry.createComponentVersionFrom(this, title,
+ revisionComment, bundle, license, sharingPolicy);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof NewComponent) {
+ NewComponent other = (NewComponent) o;
+ return registry.equals(other.registry) && id.equals(other.id);
+ }
+ return false;
+ }
+
+ public String getResourceLocation() {
+ return resource;
+ }
+
+ private static final int BASEHASH = NewComponent.class.hashCode();
+
+ @Override
+ public int hashCode() {
+ return BASEHASH ^ registry.hashCode() ^ id.hashCode();
+ }
+
+ class Version extends ComponentVersion {
+ private int version;
+ private String description;
+ private String location;
+ private SoftReference<WorkflowBundle> bundleRef;
+
+ private static final String htmlPageTemplate = "%1$s/workflows/%2$s/versions/%3$s.html";
+
+ protected Version(Integer version, String description, WorkflowBundle bundle) {
+ super(NewComponent.this);
+ this.version = version;
+ this.description = description;
+ this.bundleRef = new SoftReference<>(bundle);
+ }
+
+ protected Version(Integer version, String description) {
+ super(NewComponent.this);
+ this.version = version;
+ this.description = description;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Version) {
+ Version other = (Version) o;
+ return version == other.version
+ && NewComponent.this.equals(other.getComponent());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return NewComponent.this.hashCode() ^ (version << 16)
+ ^ (version >> 16);
+ }
+
+ @Override
+ protected Integer internalGetVersionNumber() {
+ return version;
+ }
+
+ @Override
+ protected String internalGetDescription() {
+ return description;
+ }
+
+ private String getLocationUri() throws ComponentException {
+ if (location == null)
+ location = registry.getComponentById(id, version,
+ "content-uri").getContentUri();
+ return location;
+ }
+
+ @Override
+ protected synchronized WorkflowBundle internalGetImplementation()
+ throws ComponentException {
+ if (bundleRef == null || bundleRef.get() == null) {
+ String contentUri = getLocationUri();
+ try {
+ WorkflowBundle result = system.getBundleFromUri(contentUri
+ + "?version=" + version);
+ bundleRef = new SoftReference<>(result);
+ return result;
+ } catch (Exception e) {
+ throw new ComponentException("Unable to open dataflow", e);
+ }
+ }
+ return bundleRef.get();
+ }
+
+ @Override
+ public URL getHelpURL() {
+ try {
+ return new URL(format(htmlPageTemplate,
+ registry.getRegistryBaseString(), getId(), version));
+ } catch (IllegalFormatException | MalformedURLException e) {
+ logger.error(e);
+ return null;
+ }
+ }
+ }
+
+ @Override
+ public Registry getRegistry() {
+ return registry;
+ }
+
+ @Override
+ public Family getFamily() {
+ return family;
+ }
+}