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:38:12 UTC

[04/17] incubator-taverna-plugin-bioinformatics git commit: Revert "temporarily empty repository"

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/BiomobyObjectActivityHealthChecker.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/BiomobyObjectActivityHealthChecker.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/BiomobyObjectActivityHealthChecker.java
new file mode 100644
index 0000000..7db539a
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/BiomobyObjectActivityHealthChecker.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.List;
+
+import net.sf.taverna.t2.workflowmodel.Processor;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import net.sf.taverna.t2.workflowmodel.health.HealthCheck;
+import net.sf.taverna.t2.workflowmodel.health.HealthChecker;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.visit.VisitReport.Status;
+
+import net.sf.taverna.t2.workflowmodel.health.RemoteHealthChecker;
+import net.sf.taverna.t2.workflowmodel.processor.activity.DisabledActivity;
+
+/**
+ * A health checker for the Biomoby Object activity.
+ * 
+ * @author David Withers
+ */
+public class BiomobyObjectActivityHealthChecker extends RemoteHealthChecker {
+	
+	public boolean canVisit(Object subject) {
+		if (subject == null) {
+			return false;
+		}
+		if (subject instanceof BiomobyObjectActivity) {
+			return true;
+		}
+		if (subject instanceof DisabledActivity) {
+			return (((DisabledActivity) subject).getActivity() instanceof BiomobyObjectActivity);
+		}
+		return false;
+	}
+
+	public VisitReport visit(Object o, List<Object> ancestors) {
+		Activity activity = (Activity) o;
+		BiomobyObjectActivityConfigurationBean configuration = null;
+		if (activity instanceof BiomobyObjectActivity) {
+			configuration = (BiomobyObjectActivityConfigurationBean) activity.getConfiguration();
+		} else if (activity instanceof DisabledActivity) {
+			configuration = (BiomobyObjectActivityConfigurationBean) ((DisabledActivity) activity).getActivityConfiguration();
+		}
+		return contactEndpoint(activity, configuration.getMobyEndpoint());
+
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncCgiService.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncCgiService.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncCgiService.java
new file mode 100644
index 0000000..552dd34
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncCgiService.java
@@ -0,0 +1,517 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.log4j.Logger;
+import org.biomoby.shared.MobyException;
+import org.biomoby.shared.MobyPrefixResolver;
+import org.biomoby.shared.parser.MobyTags;
+import org.biomoby.w3c.addressing.EndpointReference;
+import org.jdom.Element;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+import org.omg.lsae.notifications.AnalysisEvent;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * This class contains one method that is used to execute asynchronous HTTP POST
+ * services
+ * 
+ * @author Edward Kawas
+ * 
+ */
+public class ExecuteAsyncCgiService {
+
+	private static final String GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION = "http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest";
+	private static final String DESTROY_RESOURCE_ACTION = "http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyRequest";
+
+	private static final String RESOURCE_PROPERTIES_NS = "http://docs.oasis-open.org/wsrf/rp-2";
+	private static final String RESULT_PREFIX = "result_";
+	private static final String STATUS_PREFIX = "status_";
+	private static Logger logger = Logger
+			.getLogger(ExecuteAsyncCgiService.class);
+
+	/**
+	 * 
+	 * @param url
+	 * @param serviceName
+	 * @param xml
+	 * @return
+	 */
+	public static String executeMobyCgiAsyncService(String url,
+			String serviceName, String xml) throws MobyException {
+
+		// First, let's get the queryIds
+		org.w3c.dom.Document message = null;
+
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			dbf.setNamespaceAware(true);
+			dbf.setValidating(false);
+			DocumentBuilder db = dbf.newDocumentBuilder();
+
+			message = db.parse(new InputSource(new StringReader(xml)));
+		} catch (Throwable t) {
+			throw new MobyException("Error while parsing input query", t);
+		}
+
+		NodeList l_data = message.getElementsByTagNameNS(
+				MobyPrefixResolver.MOBY_XML_NAMESPACE, MobyTags.MOBYDATA);
+		if (l_data == null || l_data.getLength() == 0) {
+			l_data = message.getElementsByTagNameNS(
+					MobyPrefixResolver.MOBY_XML_NAMESPACE_INVALID,
+					MobyTags.MOBYDATA);
+		}
+
+		// Freeing resources
+		message = null;
+
+		if (l_data == null || l_data.getLength() == 0) {
+			throw new MobyException("Empty asynchronous MOBY query!");
+		}
+
+		int nnode = l_data.getLength();
+		String[] queryIds = new String[nnode];
+		String[] tmpQueryIds = new String[nnode];
+		String[] results = new String[nnode];
+		for (int inode = 0; inode < nnode; inode++) {
+			String queryId = null;
+
+			org.w3c.dom.Element mdata = (org.w3c.dom.Element) l_data
+					.item(inode);
+
+			queryId = mdata.getAttribute(MobyTags.QUERYID);
+			if (queryId == null || queryId.length() == 0)
+				queryId = mdata
+						.getAttributeNS(MobyPrefixResolver.MOBY_XML_NAMESPACE,
+								MobyTags.QUERYID);
+			if (queryId == null || queryId.length() == 0)
+				queryId = mdata.getAttributeNS(
+						MobyPrefixResolver.MOBY_XML_NAMESPACE_INVALID,
+						MobyTags.QUERYID);
+
+			if (queryId == null || queryId.length() == 0) {
+				throw new MobyException(
+						"Unable to extract queryId for outgoing MOBY message");
+			}
+
+			tmpQueryIds[inode] = queryIds[inode] = queryId;
+			results[inode] = null;
+		}
+
+		// Freeing resources
+		l_data = null;
+
+		// Second, let's launch
+		EndpointReference epr = launchCgiAsyncService(url, xml);
+
+		// Third, waiting for the results
+		try {
+			// FIXME - add appropriate values here
+			long pollingInterval = 1000L;
+			double backoff = 1.0;
+
+			// Max: one minute pollings
+			long maxPollingInterval = 60000L;
+
+			// Min: one second
+			if (pollingInterval <= 0L)
+				pollingInterval = 1000L;
+
+			// Backoff: must be bigger than 1.0
+			if (backoff <= 1.0)
+				backoff = 1.5;
+
+			do {
+				try {
+					Thread.sleep(pollingInterval);
+				} catch (InterruptedException ie) {
+					// DoNothing(R)
+				}
+
+				if (pollingInterval != maxPollingInterval) {
+					pollingInterval = (long) ((double) pollingInterval * backoff);
+					if (pollingInterval > maxPollingInterval) {
+						pollingInterval = maxPollingInterval;
+					}
+				}
+			} while (pollAsyncCgiService(serviceName, url, epr, tmpQueryIds,
+					results));
+		} finally {
+
+			// Call destroy on this service ....
+			freeCgiAsyncResources(url, epr);
+
+		}
+
+		// Fourth, assembling back the results
+
+		// Results array already contains mobyData
+		Element[] mobydatas = new Element[results.length];
+		for (int x = 0; x < results.length; x++) {
+			// TODO remove the extra wrapping from our result
+			try {
+				Element inputElement = XMLUtilities.getDOMDocument(results[x])
+						.getRootElement();
+				if (inputElement.getName().indexOf(
+						"GetMultipleResourcePropertiesResponse") >= 0)
+					if (inputElement.getChildren().size() > 0)
+						inputElement = (Element) inputElement.getChildren()
+								.get(0);
+				if (inputElement.getName().indexOf("result_") >= 0)
+					if (inputElement.getChildren().size() > 0)
+						inputElement = (Element) inputElement.getChildren()
+								.get(0);
+				// replace results[x]
+				mobydatas[x] = inputElement;
+			} catch (MobyException e) {
+				// TODO what should i do?
+			}
+		}
+		Element e = null;
+		try {
+			e = XMLUtilities.createMultipleInvokations(mobydatas);
+		} catch (Exception ex) {
+			logger
+					.error("There was a problem creating our XML message ...",
+							ex);
+		}
+		// Fifth, returning results
+		return e == null ? "" : new XMLOutputter(Format.getPrettyFormat())
+				.outputString(e);
+	}
+
+	private static void freeCgiAsyncResources(String endpoint,
+			EndpointReference epr) throws MobyException {
+		// construct the Httpclient
+		HttpClient client = new HttpClient();
+		client.getParams().setParameter("http.useragent", "jMoby/Taverna2");
+		// create the post method
+		PostMethod method = new PostMethod(endpoint + "/destroy");
+
+		// put our data in the request
+		RequestEntity entity;
+		try {
+			entity = new StringRequestEntity(
+					"<Destroy xmlns=\"http://docs.oasis-open.org/wsrf/rl-2\"/>",
+					"text/xml", null);
+		} catch (UnsupportedEncodingException e) {
+			throw new MobyException("Problem posting data to webservice", e);
+		}
+		method.setRequestEntity(entity);
+
+		// set the header
+		StringBuffer httpheader = new StringBuffer();
+		httpheader.append("<moby-wsrf>");
+		httpheader
+				.append("<wsa:Action xmlns:wsa=\"http://www.w3.org/2005/08/addressing\">"
+						+ DESTROY_RESOURCE_ACTION + "</wsa:Action>");
+		httpheader
+				.append("<wsa:To xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsu:Id=\"To\">"
+						+ endpoint + "</wsa:To>");
+		httpheader
+				.append("<mobyws:ServiceInvocationId xmlns:mobyws=\"http://biomoby.org/\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsa:IsReferenceParameter=\"true\">"
+						+ epr.getServiceInvocationId()
+						+ "</mobyws:ServiceInvocationId>");
+		httpheader.append("</moby-wsrf>");
+		method.addRequestHeader("moby-wsrf", httpheader.toString().replaceAll(
+				"\r\n", ""));
+		// retry up to 10 times
+		client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
+				new DefaultHttpMethodRetryHandler(10, true));
+
+		// call the method
+		try {
+			int result = client.executeMethod(method);
+			if (result != HttpStatus.SC_OK)
+				throw new MobyException(
+						"Async HTTP POST service returned code: " + result
+								+ "\n" + method.getStatusLine());
+		} catch (IOException e) {
+			throw new MobyException("Problem reading response from webservice",
+					e);
+		} finally {
+			// Release current connection to the connection pool once you are
+			// done
+			method.releaseConnection();
+		}
+	}
+
+	/**
+	 * 
+	 * @param endpoint
+	 *            the url to the service to call
+	 * @param xml
+	 *            the BioMOBY input message
+	 * @return EndpointReference the EPR returned by the service
+	 * @throws MobyException
+	 */
+	private static EndpointReference launchCgiAsyncService(String endpoint,
+			String xml) throws MobyException {
+		// construct the Httpclient
+		HttpClient client = new HttpClient();
+		client.getParams().setParameter("http.useragent", "jMoby/Taverna2");
+		// create the post method
+		PostMethod method = new PostMethod(endpoint);
+
+		// put our data in the request
+		RequestEntity entity;
+		try {
+			entity = new StringRequestEntity(xml, "text/xml", null);
+		} catch (UnsupportedEncodingException e) {
+			throw new MobyException("Problem posting data to webservice", e);
+		}
+		method.setRequestEntity(entity);
+
+		// retry up to 10 times
+		client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
+				new DefaultHttpMethodRetryHandler(10, true));
+
+		// call the method
+		try {
+			int result = client.executeMethod(method);
+			if (result != HttpStatus.SC_OK)
+				throw new MobyException(
+						"Async HTTP POST service returned code: " + result
+								+ "\n" + method.getStatusLine());
+			return EndpointReference.createFromXML(method.getResponseHeader(
+					"moby-wsrf").getValue());
+		} catch (IOException e) {
+			throw new MobyException("Problem reading response from webservice",
+					e);
+		} finally {
+			// Release current connection to the connection pool once you are
+			// done
+			method.releaseConnection();
+		}
+	}
+
+	private static boolean pollAsyncCgiService(String msName, String url,
+			EndpointReference epr, String[] queryIds, String[] result)
+			throws MobyException {
+		// Needed to remap results
+		HashMap<String, Integer> queryMap = new HashMap<String, Integer>();
+		for (int qi = 0; qi < queryIds.length; qi++) {
+			String queryId = queryIds[qi];
+			if (queryId != null)
+				queryMap.put(queryId, new Integer(qi));
+		}
+
+		if (queryMap.size() == 0)
+			return false;
+
+		// construct the GetMultipleResourceProperties XML
+		StringBuffer xml = new StringBuffer();
+		xml.append("<wsrf-rp:GetMultipleResourceProperties xmlns:wsrf-rp='"
+				+ RESOURCE_PROPERTIES_NS
+				+ "' xmlns:mobyws='http://biomoby.org/'>");
+		for (String q : queryMap.keySet())
+			xml.append("<wsrf-rp:ResourceProperty>mobyws:" + STATUS_PREFIX + q
+					+ "</wsrf-rp:ResourceProperty>");
+		xml.append("</wsrf-rp:GetMultipleResourceProperties>");
+
+		StringBuffer httpheader = new StringBuffer();
+		httpheader.append("<moby-wsrf>");
+		httpheader
+				.append("<wsa:Action xmlns:wsa=\"http://www.w3.org/2005/08/addressing\">"
+						+ GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION
+						+ "</wsa:Action>");
+		httpheader
+				.append("<wsa:To xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsu:Id=\"To\">"
+						+ url + "</wsa:To>");
+		httpheader
+				.append("<mobyws:ServiceInvocationId xmlns:mobyws=\"http://biomoby.org/\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsa:IsReferenceParameter=\"true\">"
+						+ epr.getServiceInvocationId()
+						+ "</mobyws:ServiceInvocationId>");
+		httpheader.append("</moby-wsrf>");
+
+		AnalysisEvent[] l_ae = null;
+		// First, status from queries
+		String response = "";
+		// construct the Httpclient
+		HttpClient client = new HttpClient();
+		client.getParams().setParameter("http.useragent", "jMoby/Taverna2");
+		// create the post method
+		PostMethod method = new PostMethod(url + "/status");
+		// add the moby-wsrf header (with no newlines)
+		method.addRequestHeader("moby-wsrf", httpheader.toString().replaceAll(
+				"\r\n", ""));
+
+		// put our data in the request
+		RequestEntity entity;
+		try {
+			entity = new StringRequestEntity(xml.toString(), "text/xml", null);
+		} catch (UnsupportedEncodingException e) {
+			throw new MobyException("Problem posting data to webservice", e);
+		}
+		method.setRequestEntity(entity);
+
+		// retry up to 10 times
+		client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
+				new DefaultHttpMethodRetryHandler(10, true));
+
+		// call the method
+		try {
+			if (client.executeMethod(method) != HttpStatus.SC_OK)
+				throw new MobyException(
+						"Async HTTP POST service returned code: "
+								+ method.getStatusCode() + "\n"
+								+ method.getStatusLine()
+								+ "\nduring our polling request");
+			response = stream2String(method.getResponseBodyAsStream());
+		} catch (IOException e) {
+			throw new MobyException("Problem reading response from webservice",
+					e);
+		} finally {
+			// Release current connection to the connection pool once you
+			// are
+			// done
+			method.releaseConnection();
+		}
+
+		if (response != null) {
+			l_ae = AnalysisEvent.createFromXML(response);
+		}
+
+		if (l_ae == null || l_ae.length == 0) {
+			new MobyException(
+					"Troubles while checking asynchronous MOBY job status from service "
+							+ msName);
+		}
+
+		ArrayList<String> finishedQueries = new ArrayList<String>();
+		// Second, gather those finished queries
+		for (int iae = 0; iae < l_ae.length; iae++) {
+			AnalysisEvent ae = l_ae[iae];
+			if (ae.isCompleted()) {
+				String queryId = ae.getQueryId();
+				if (!queryMap.containsKey(queryId)) {
+					throw new MobyException(
+							"Invalid result queryId on asynchronous MOBY job status fetched from "
+									+ msName);
+				}
+				finishedQueries.add(queryId);
+			}
+		}
+
+		// Third, let's fetch the results from the finished queries
+		if (finishedQueries.size() > 0) {
+			String[] resQueryIds = finishedQueries.toArray(new String[0]);
+			for (int x = 0; x < resQueryIds.length; x++) {
+				// construct the GetMultipleResourceProperties XML
+				xml = new StringBuffer();
+				xml
+						.append("<wsrf-rp:GetMultipleResourceProperties xmlns:wsrf-rp='"
+								+ RESOURCE_PROPERTIES_NS
+								+ "' xmlns:mobyws='http://biomoby.org/'>");
+				for (String q : resQueryIds)
+					xml.append("<wsrf-rp:ResourceProperty>mobyws:" + RESULT_PREFIX + q
+							+ "</wsrf-rp:ResourceProperty>");
+				xml.append("</wsrf-rp:GetMultipleResourceProperties>");
+
+				httpheader = new StringBuffer();
+				httpheader.append("<moby-wsrf>");
+				httpheader
+						.append("<wsa:Action xmlns:wsa=\"http://www.w3.org/2005/08/addressing\">"
+								+ GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION
+								+ "</wsa:Action>");
+				httpheader
+						.append("<wsa:To xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsu:Id=\"To\">"
+								+ url + "</wsa:To>");
+				httpheader
+						.append("<mobyws:ServiceInvocationId xmlns:mobyws=\"http://biomoby.org/\" xmlns:wsa=\"http://www.w3.org/2005/08/addressing\" wsa:IsReferenceParameter=\"true\">"
+								+ epr.getServiceInvocationId()
+								+ "</mobyws:ServiceInvocationId>");
+				httpheader.append("</moby-wsrf>");
+				client = new HttpClient();
+				client.getParams().setParameter("http.useragent",
+						"jMoby/Taverna2");
+				// create the post method
+				method = new PostMethod(url + "/results");
+				// add the moby-wsrf header (with no newlines)
+				method.addRequestHeader("moby-wsrf", httpheader.toString()
+						.replaceAll("\r\n", ""));
+
+				// put our data in the request
+				entity = null;
+				try {
+					entity = new StringRequestEntity(xml.toString(),
+							"text/xml", null);
+				} catch (UnsupportedEncodingException e) {
+					throw new MobyException(
+							"Problem posting data to webservice", e);
+				}
+				method.setRequestEntity(entity);
+
+				// retry up to 10 times
+				client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
+						new DefaultHttpMethodRetryHandler(10, true));
+
+				// call the method
+				try {
+					if (client.executeMethod(method) != HttpStatus.SC_OK)
+						throw new MobyException(
+								"Async HTTP POST service returned code: "
+										+ method.getStatusCode() + "\n"
+										+ method.getStatusLine()
+										+ "\nduring our polling request");
+					// place the result in the array
+					result[x] = stream2String(method.getResponseBodyAsStream());
+					// Marking as null
+					queryIds[x] = null;
+				} catch (IOException e) {
+					logger.warn("Problem getting result from webservice\n"
+							+ e.getMessage());
+				} finally {
+					// Release current connection
+					method.releaseConnection();
+				}
+			}
+
+		}
+		return finishedQueries.size() != queryMap.size();
+	}
+
+	private static String stream2String(InputStream is) {
+		BufferedReader br = new BufferedReader(new InputStreamReader(is));
+		StringBuilder sb = new StringBuilder();
+		String line = null;
+		String newline = System.getProperty("line.separator");
+		try {
+			while ((line = br.readLine()) != null) {
+				sb.append(line + newline);
+			}
+		} catch (IOException e) {
+			logger.warn("Exception reading input stream ...", e);
+		} finally {
+			try {
+				br.close();
+			} catch (IOException e) {
+				logger.warn("Exception closing input stream ...", e);
+			}
+		}
+		return sb.toString();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncMobyService.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncMobyService.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncMobyService.java
new file mode 100644
index 0000000..10c76bc
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteAsyncMobyService.java
@@ -0,0 +1,695 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPBody;
+import javax.xml.soap.SOAPElement;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.soap.SOAPPart;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.Dispatch;
+import javax.xml.ws.Service;
+import javax.xml.ws.soap.SOAPBinding;
+
+import org.apache.log4j.Logger;
+import org.biomoby.shared.MobyException;
+import org.biomoby.shared.MobyPrefixResolver;
+import org.biomoby.shared.MobyService;
+import org.biomoby.shared.parser.MobyTags;
+import org.biomoby.w3c.addressing.EndpointReference;
+import org.omg.lsae.notifications.AnalysisEvent;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+
+/**
+ * This class contains one method that is used to execute asynchronous moby
+ * services
+ * 
+ * @author Edward Kawas
+ * 
+ */
+
+public class ExecuteAsyncMobyService {
+
+	/* async constants */
+	private static final String GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION = "http://docs.oasis-open.org/wsrf/rpw-2/GetMultipleResourceProperties/GetMultipleResourcePropertiesRequest";
+	private static final String DESTROY_RESOURCE_ACTION = "http://docs.oasis-open.org/wsrf/rlw-2/ImmediateResourceTermination/DestroyRequest";
+
+	private static final String RESOURCE_PROPERTIES_NS = "http://docs.oasis-open.org/wsrf/rp-2";
+	private static final String RESOURCE_LIFETIME_NS = "http://docs.oasis-open.org/wsrf/rl-2";
+
+	@SuppressWarnings("unused")
+	private static final String XMLNS_NS = "http://www.w3.org/2000/xmlns/";
+	private static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
+	private static final String WSA_NS = "http://www.w3.org/2005/08/addressing";
+	private static final String WSU_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
+	private static final String ANON_URI = WSA_NS + "/anonymous";
+	private static final String RESULT_PREFIX = "result_";
+	private static final String STATUS_PREFIX = "status_";
+	
+	private static Logger logger = Logger.getLogger(ExecuteAsyncMobyService.class);
+	/**
+	 * This method does the same as getMultipleResourceProperties, with the
+	 * difference that it returns an String instead of a SOAPPart object. The
+	 * result is the serialization of the SOAPPart output obtained from
+	 * getMultipleResourceProperties.
+	 * 
+	 * @param msName
+	 *            The MOBY service name
+	 * @param queryIds
+	 *            The array with the queryIds to use. It may contain null
+	 *            strings
+	 * @param epr
+	 *            The EndpointReference object which helds the MOBY asynchronous
+	 *            job information
+	 * @param asResult
+	 *            If this parameter is true, then this call fetches the results
+	 *            associated to the input queryIds. If it is false, then this
+	 *            call only asks for the job status.
+	 * @return When at least one of the strings from queryIds array was not
+	 *         null, an String with the serialized answer from the service.
+	 *         Otherwise, it returns null.
+	 * @throws SOAPException
+	 */
+	private static String getMultipleResourcePropertiesAsString(String msName,
+			String[] queryIds, EndpointReference epr, boolean asResult)
+			throws TransformerConfigurationException, SOAPException,
+			TransformerException {
+		SOAPPart result = getMultipleResourceProperties(msName, queryIds, epr,
+				asResult);
+		if (result == null)
+			return null;
+		Transformer tr = TransformerFactory.newInstance().newTransformer();
+		tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+
+		DOMSource dombody = new DOMSource(result);
+
+		StringWriter sw = new StringWriter();
+		tr.transform(dombody, new StreamResult(sw));
+
+		return sw.toString();
+	}
+
+	/**
+	 * This method does the check and fetch work related to asynchronous
+	 * services. When all the results are fetched, it returns false. When some
+	 * recheck must be issued, it returns true.
+	 * 
+	 * @param msName
+	 *            The MOBY service name
+	 * @param epr
+	 *            The EndpointReference, used for the queries
+	 * @param queryIds
+	 *            The array which holds the queryIds to ask for. It can contain
+	 *            null strings.
+	 * @param result
+	 *            The array which will hold the mobyData results. This one must
+	 *            have the same size as queryIds array.
+	 * @return true, if we need more checking iterations. Otherwise, false
+	 * @throws MobyException
+	 */
+	private static boolean checkMobyAsyncJobsStatus(String msName,
+			EndpointReference epr, String[] queryIds,
+			org.w3c.dom.Element[] result) throws MobyException {
+		// Needed to remap results
+		HashMap<String, Integer> queryMap = new HashMap<String, Integer>();
+		for (int qi = 0; qi < queryIds.length; qi++) {
+			String queryId = queryIds[qi];
+			if (queryId != null)
+				queryMap.put(queryId, new Integer(qi));
+		}
+
+		if (queryMap.size() == 0)
+			return false;
+
+		try {
+			AnalysisEvent[] l_ae = null;
+			// First, status from queries
+			String response = getMultipleResourcePropertiesAsString(msName,
+					queryIds, epr, false);
+			if (response != null) {
+				l_ae = AnalysisEvent.createFromXML(response);
+			}
+
+			if (l_ae == null || l_ae.length == 0) {
+				new MobyException(
+						"Troubles while checking asynchronous MOBY job status from service "
+								+ msName);
+			}
+
+			ArrayList<String> finishedQueries = new ArrayList<String>();
+			// Second, gather those finished queries
+			for (int iae = 0; iae < l_ae.length; iae++) {
+				AnalysisEvent ae = l_ae[iae];
+				if (ae.isCompleted()) {
+					String queryId = ae.getQueryId();
+					if (!queryMap.containsKey(queryId)) {
+						throw new MobyException(
+								"Invalid result queryId on asynchronous MOBY job status fetched from "
+										+ msName);
+					}
+					finishedQueries.add(queryId);
+				}
+			}
+
+			// Third, let's fetch the results from the finished queries
+			if (finishedQueries.size() > 0) {
+				String[] resQueryIds = finishedQueries.toArray(new String[0]);
+				SOAPPart soapDOM = getMultipleResourceProperties(msName,
+						resQueryIds, epr, true);
+				NodeList l_mul = soapDOM.getElementsByTagNameNS(
+						RESOURCE_PROPERTIES_NS,
+						"GetMultipleResourcePropertiesResponse");
+				if (l_mul == null || l_mul.getLength() == 0) {
+					throw new MobyException(
+							"Error while fetching asynchronous MOBY results from "
+									+ msName);
+				}
+
+				org.w3c.dom.Element mul = (org.w3c.dom.Element) l_mul.item(0);
+				for (org.w3c.dom.Node child = mul.getFirstChild(); child != null; child = child
+						.getNextSibling()) {
+					if (child.getNodeType() == Node.ELEMENT_NODE
+							&& MobyService.BIOMOBY_SERVICE_URI.equals(child
+									.getNamespaceURI())) {
+						String preQueryId = child.getLocalName();
+						int subpos = preQueryId.indexOf(RESULT_PREFIX);
+						if (subpos != 0) {
+							throw new MobyException(
+									"Invalid result prefix on asynchronous MOBY job results fetched from "
+											+ msName);
+						}
+						String queryId = preQueryId.substring(RESULT_PREFIX
+								.length());
+						if (!queryMap.containsKey(queryId)) {
+							throw new MobyException(
+									"Invalid result queryId on asynchronous MOBY job results fetched from "
+											+ msName);
+						}
+
+						org.w3c.dom.Element elchild = (org.w3c.dom.Element) child;
+						NodeList l_moby = elchild.getElementsByTagNameNS(
+								MobyPrefixResolver.MOBY_XML_NAMESPACE,
+								MobyTags.MOBYDATA);
+						if (l_moby == null || l_moby.getLength() == 0)
+							l_moby = elchild
+									.getElementsByTagNameNS(
+											MobyPrefixResolver.MOBY_XML_NAMESPACE_INVALID,
+											MobyTags.MOBYDATA);
+
+						if (l_moby == null || l_moby.getLength() == 0) {
+							throw new MobyException(
+									"Recovered empty payload from asynchronous MOBY service "
+											+ msName);
+						}
+						Integer queryPos = queryMap.get(queryId);
+						result[queryPos] = (org.w3c.dom.Element) l_moby.item(0);
+						// Marking as null
+						queryIds[queryPos] = null;
+					}
+				}
+			}
+
+			return finishedQueries.size() != queryMap.size();
+		} catch (SOAPException se) {
+			throw new MobyException("Error while querying MOBY job status", se);
+		} catch (TransformerConfigurationException tce) {
+			throw new MobyException(
+					"Error while preparing to parse MOBY job status", tce);
+		} catch (TransformerException te) {
+			throw new MobyException("Error while parsing MOBY job status", te);
+		}
+	}
+
+	/**
+	 * This method calls the input MOBY service using the asynchronous protocol.
+	 * 
+	 * @param endpoint
+	 *            The endpoint of the service.
+	 * @param msName
+	 *            The MOBY service name.
+	 * @param mobyXML
+	 *            The MOBY payload to be sent to the service.
+	 * @return The MOBY payload with the results from the service.
+	 * @throws MobyException
+	 */
+	public static String executeMobyAsyncService(String endpoint, String msName,
+			String mobyXML) throws MobyException {
+		// First, let's get the queryIds
+		org.w3c.dom.Document message = null;
+
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			dbf.setNamespaceAware(true);
+			dbf.setValidating(false);
+			DocumentBuilder db = dbf.newDocumentBuilder();
+
+			message = db.parse(new InputSource(new StringReader(mobyXML)));
+		} catch (Throwable t) {
+			throw new MobyException("Error while parsing input query", t);
+		}
+
+		NodeList l_data = message.getElementsByTagNameNS(
+				MobyPrefixResolver.MOBY_XML_NAMESPACE, MobyTags.MOBYDATA);
+		if (l_data == null || l_data.getLength() == 0) {
+			l_data = message.getElementsByTagNameNS(
+					MobyPrefixResolver.MOBY_XML_NAMESPACE_INVALID,
+					MobyTags.MOBYDATA);
+		}
+
+		// Freeing resources
+		message = null;
+
+		if (l_data == null || l_data.getLength() == 0) {
+			throw new MobyException("Empty asynchronous MOBY query!");
+		}
+
+		int nnode = l_data.getLength();
+		String[] queryIds = new String[nnode];
+		String[] tmpQueryIds = new String[nnode];
+		org.w3c.dom.Element[] results = new org.w3c.dom.Element[nnode];
+		for (int inode = 0; inode < nnode; inode++) {
+			String queryId = null;
+
+			org.w3c.dom.Element mdata = (org.w3c.dom.Element) l_data
+					.item(inode);
+
+			queryId = mdata.getAttribute(MobyTags.QUERYID);
+			if (queryId == null || queryId.length() == 0)
+				queryId = mdata
+						.getAttributeNS(MobyPrefixResolver.MOBY_XML_NAMESPACE,
+								MobyTags.QUERYID);
+			if (queryId == null || queryId.length() == 0)
+				queryId = mdata.getAttributeNS(
+						MobyPrefixResolver.MOBY_XML_NAMESPACE_INVALID,
+						MobyTags.QUERYID);
+
+			if (queryId == null || queryId.length() == 0) {
+				throw new MobyException(
+						"Unable to extract queryId for outgoing MOBY message");
+			}
+
+			tmpQueryIds[inode] = queryIds[inode] = queryId;
+			results[inode] = null;
+		}
+
+		// Freeing resources
+		l_data = null;
+
+		// Second, let's launch
+		EndpointReference epr = launchMobyAsyncService(endpoint, msName,
+				mobyXML);
+
+		// Third, waiting for the results
+		try {
+			// FIXME - add appropriate values here
+			long pollingInterval = 1000L; // proc.getRetryDelay();
+			double backoff = 1.0;// proc.getBackoff();
+
+			// Max: one minute pollings
+			long maxPollingInterval = 60000L;
+
+			// Min: one second
+			if (pollingInterval <= 0L)
+				pollingInterval = 1000L;
+
+			// Backoff: must be bigger than 1.0
+			if (backoff <= 1.0)
+				backoff = 1.5;
+
+			do {
+				try {
+					Thread.sleep(pollingInterval);
+				} catch (InterruptedException ie) {
+					// DoNothing(R)
+				}
+
+				if (pollingInterval != maxPollingInterval) {
+					pollingInterval = (long) ((double) pollingInterval * backoff/*
+																				 * proc.
+																				 * getBackoff
+																				 * (
+																				 * )
+																				 */);
+					if (pollingInterval > maxPollingInterval) {
+						pollingInterval = maxPollingInterval;
+					}
+				}
+			} while (checkMobyAsyncJobsStatus(msName, epr, tmpQueryIds, results));
+		} finally {
+			try {
+				freeAsyncResources(msName, epr);
+			} catch (SOAPException se) {
+				logger.info(
+						"An error was fired while freeing MOBY asynchronous resources from "
+								+ msName, se);
+			}
+		}
+
+		// Fourth, assembling back the results
+		org.w3c.dom.Document resdoc = null;
+		try {
+			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			dbf.setNamespaceAware(true);
+			dbf.setValidating(false);
+			DocumentBuilder db = dbf.newDocumentBuilder();
+			resdoc = db.newDocument();
+
+			org.w3c.dom.Element mobyroot = resdoc.createElementNS(
+					MobyPrefixResolver.MOBY_XML_NAMESPACE, MobyTags.MOBY);
+			resdoc.appendChild(mobyroot);
+			org.w3c.dom.Element mobycontent = resdoc
+					.createElementNS(MobyPrefixResolver.MOBY_XML_NAMESPACE,
+							MobyTags.MOBYCONTENT);
+			mobyroot.appendChild(mobycontent);
+
+			// Results array already contains mobyData
+
+			for (org.w3c.dom.Element result : results) {
+				mobycontent.appendChild(resdoc.importNode(result, true));
+			}
+		} catch (Throwable t) {
+			throw new MobyException("Error while assembling output", t);
+		}
+
+		// Fifth, returning results
+		try {
+			Transformer tr = TransformerFactory.newInstance().newTransformer();
+			tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+
+			DOMSource dombody = new DOMSource(resdoc);
+
+			StringWriter sw = new StringWriter();
+			tr.transform(dombody, new StreamResult(sw));
+
+			return sw.toString();
+		} catch (Throwable t) {
+			throw new MobyException("Error while assembling output", t);
+		}
+	}
+	
+	/**
+	 * This method free the asynchronous MOBY resources associated to the job
+	 * identifier tied to the EndpointReference object passed as input.
+	 * 
+	 * @param msName
+	 *            The MOBY service name
+	 * @param epr
+	 *            The EndpointReference object which holds the MOBY asynchronous
+	 *            job information
+	 * @throws SOAPException
+	 */
+	private static void freeAsyncResources(String msName, EndpointReference epr)
+			throws SOAPException {
+		Service service = Service.create(new QName(
+				MobyService.BIOMOBY_SERVICE_URI, msName + "Service"));
+		QName mQName = new QName(MobyService.BIOMOBY_SERVICE_URI,
+				"WSRF_Operations_Port");
+		service.addPort(mQName, SOAPBinding.SOAP11HTTP_BINDING, epr
+				.getAddress());
+
+		Dispatch<SOAPMessage> dispatch = service.createDispatch(mQName,
+				SOAPMessage.class, Service.Mode.MESSAGE);
+		Map<String, Object> rc = dispatch.getRequestContext();
+		rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, new Boolean(true));
+		rc.put(BindingProvider.SOAPACTION_URI_PROPERTY,
+				GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION);
+
+		MessageFactory mf = MessageFactory.newInstance();
+		SOAPMessage request = mf.createMessage();
+		SOAPPart part = request.getSOAPPart();
+
+		String mobyPrefix = "mobyws";
+		String wsaPrefix = "wsa";
+		String wsuPrefix = "wsu";
+		// Obtain the SOAPEnvelope and header and body elements.
+		SOAPEnvelope env = part.getEnvelope();
+		SOAPHeader header = env.getHeader();
+		SOAPBody body = env.getBody();
+
+		header.addNamespaceDeclaration(mobyPrefix,
+				MobyService.BIOMOBY_SERVICE_URI);
+		header.addNamespaceDeclaration(wsaPrefix, WSA_NS);
+		header.addNamespaceDeclaration(wsuPrefix, WSU_NS);
+		// This is for the action
+		SOAPElement actionRoot = header.addChildElement("Action", wsaPrefix,
+				WSA_NS);
+		actionRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS),
+				"Action");
+		actionRoot.addTextNode(DESTROY_RESOURCE_ACTION);
+
+		// This is for the To
+		SOAPElement toRoot = header.addChildElement("To", wsaPrefix, WSA_NS);
+		toRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS), "To");
+		toRoot.addTextNode(epr.getAddress());
+
+		// And this is for the mobyws
+		SOAPElement mobywsRoot = header.addChildElement("ServiceInvocationId",
+				mobyPrefix, MobyService.BIOMOBY_SERVICE_URI);
+		mobywsRoot.addNamespaceDeclaration(wsaPrefix, WSA_NS);
+		mobywsRoot.addAttribute(env.createName("isReferenceParameter",
+				wsaPrefix, WSA_NS), "true");
+		mobywsRoot.addTextNode(epr.getServiceInvocationId());
+
+		// At last, the replyto
+		SOAPElement replyRoot = header.addChildElement("ReplyTo", wsaPrefix,
+				WSA_NS);
+		replyRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS),
+				"ReplyTo");
+		SOAPElement addr = replyRoot.addChildElement("Address", wsaPrefix,
+				WSA_NS);
+		addr.addTextNode(ANON_URI);
+
+		// Let's disable the headers
+		// ((WSBindingProvider)dispatch).setOutboundHeaders(headers);
+
+		// Now the SOAP body
+		body.addChildElement("Destroy", "rl", RESOURCE_LIFETIME_NS);
+
+		request.saveChanges();
+		// We don't mind what it is returned
+		dispatch.invoke(request);
+	}
+	
+	/**
+	 * This method is used to launch an asynchronous MOBY job.
+	 * 
+	 * @param endpoint
+	 *            The endpoint of the service.
+	 * @param msName
+	 *            The MOBY service name.
+	 * @param mobyXML
+	 *            The MOBY payload to be sent to the service.
+	 * @return The EndpointReference object which helds the details of the MOBY
+	 *         asynchronous job.
+	 * @throws MobyException
+	 */
+	private static EndpointReference launchMobyAsyncService(String endpoint,
+			String msName, String mobyXML) throws MobyException {
+		try {
+			Service service = Service.create(new QName(
+					MobyService.BIOMOBY_SERVICE_URI, msName + "Service"));
+			QName mQName = new QName(MobyService.BIOMOBY_SERVICE_URI, msName
+					+ "Port");
+
+			service.addPort(mQName, SOAPBinding.SOAP11HTTP_BINDING, endpoint);
+			Dispatch<SOAPMessage> dispatch = service.createDispatch(mQName,
+					SOAPMessage.class, Service.Mode.MESSAGE);
+			Map<String, Object> rc = dispatch.getRequestContext();
+			rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, new Boolean(true));
+			rc.put(BindingProvider.SOAPACTION_URI_PROPERTY,
+					MobyService.BIOMOBY_SERVICE_URI + "#" + msName + "_submit");
+
+			MessageFactory mf = MessageFactory.newInstance();
+			SOAPMessage request = mf.createMessage();
+			SOAPPart part = request.getSOAPPart();
+
+			String mobyPrefix = "mobyws";
+			String xsiPrefix = "xsi";
+
+			// Obtain the SOAPEnvelope and header and body elements.
+			SOAPEnvelope env = part.getEnvelope();
+			SOAPBody body = env.getBody();
+
+			// Now the SOAP body
+			body.addNamespaceDeclaration(mobyPrefix,
+					MobyService.BIOMOBY_SERVICE_URI);
+			SOAPElement rootMessage = body.addChildElement(msName + "_submit",
+					mobyPrefix, MobyService.BIOMOBY_SERVICE_URI);
+			SOAPElement data = rootMessage.addChildElement("data", mobyPrefix,
+					MobyService.BIOMOBY_SERVICE_URI);
+			data.addNamespaceDeclaration(xsiPrefix,
+					MobyPrefixResolver.XSI_NAMESPACE2001);
+			data.addNamespaceDeclaration("xsd", XSD_NS);
+			data.addAttribute(env.createName("type", xsiPrefix,
+					MobyPrefixResolver.XSI_NAMESPACE2001), "xsd:string");
+			data.addTextNode(mobyXML);
+
+			request.saveChanges();
+			SOAPMessage outputMessage = dispatch.invoke(request);
+			DOMSource output = new DOMSource(outputMessage.getSOAPPart()
+					.getEnvelope());
+
+			StringWriter sw = new StringWriter();
+			Transformer tr = TransformerFactory.newInstance().newTransformer();
+			tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+			tr.transform(output, new StreamResult(sw));
+
+			String response = sw.toString();
+			return EndpointReference.createFromXML(response);
+		} catch (SOAPException pce) {
+			throw new MobyException(
+					"Unable to create SOAP document builder for MOBY asynchronous call submission",
+					pce);
+		} catch (TransformerConfigurationException tce) {
+			throw new MobyException(
+					"Unable to create transformer factory for MOBY asynchronous call response",
+					tce);
+		} catch (TransformerException te) {
+			throw new MobyException(
+					"Unable to create transformer for MOBY asynchronous call response",
+					te);
+		}
+	}
+
+	
+
+	/**
+	 * This method issues WSRF getMultipleResourceProperties calls. As this call
+	 * is used in BioMOBY for polling and for result fetching, it has an
+	 * additional parameter which handles the call mode.
+	 * 
+	 * @param msName
+	 *            The MOBY service name
+	 * @param queryIds
+	 *            The array with the queryIds to use. It may contain null
+	 *            strings
+	 * @param epr
+	 *            The EndpointReference object which helds the MOBY asynchronous
+	 *            job information
+	 * @param asResult
+	 *            If this parameter is true, then this call fetches the results
+	 *            associated to the input queryIds. If it is false, then this
+	 *            call only asks for the job status.
+	 * @return When at least one of the strings from queryIds array was not
+	 *         null, a SOAPPart object is returned with the answer for the
+	 *         request issued to the MOBY service. Otherwise, it returns null.
+	 * @throws SOAPException
+	 */
+	private static SOAPPart getMultipleResourceProperties(String msName,
+			String[] queryIds, EndpointReference epr, boolean asResult)
+			throws SOAPException {
+		String op = asResult ? RESULT_PREFIX : STATUS_PREFIX;
+
+		Service service = Service.create(new QName(
+				MobyService.BIOMOBY_SERVICE_URI, msName + "Service"));
+		QName mQName = new QName(MobyService.BIOMOBY_SERVICE_URI,
+				"WSRF_Operations_Port");
+		service.addPort(mQName, SOAPBinding.SOAP11HTTP_BINDING, epr
+				.getAddress());
+
+		Dispatch<SOAPMessage> dispatch = service.createDispatch(mQName,
+				SOAPMessage.class, Service.Mode.MESSAGE);
+		Map<String, Object> rc = dispatch.getRequestContext();
+		rc.put(BindingProvider.SOAPACTION_USE_PROPERTY, new Boolean(true));
+		rc.put(BindingProvider.SOAPACTION_URI_PROPERTY,
+				GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION);
+
+		MessageFactory mf = MessageFactory.newInstance();
+		SOAPMessage request = mf.createMessage();
+		SOAPPart part = request.getSOAPPart();
+
+		String mobyPrefix = "mobyws";
+		String wsaPrefix = "wsa";
+		String wsuPrefix = "wsu";
+		// Obtain the SOAPEnvelope and header and body elements.
+		SOAPEnvelope env = part.getEnvelope();
+		SOAPHeader header = env.getHeader();
+		SOAPBody body = env.getBody();
+
+		header.addNamespaceDeclaration(mobyPrefix,
+				MobyService.BIOMOBY_SERVICE_URI);
+		header.addNamespaceDeclaration(wsaPrefix, WSA_NS);
+		header.addNamespaceDeclaration(wsuPrefix, WSU_NS);
+		// This is for the action
+		SOAPElement actionRoot = header.addChildElement("Action", wsaPrefix,
+				WSA_NS);
+		actionRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS),
+				"Action");
+		actionRoot.addTextNode(GET_MULTIPLE_RESOURCE_PROPERTIES_ACTION);
+
+		// This is for the To
+		SOAPElement toRoot = header.addChildElement("To", wsaPrefix, WSA_NS);
+		toRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS), "To");
+		toRoot.addTextNode(epr.getAddress());
+
+		// And this is for the mobyws
+		SOAPElement mobywsRoot = header.addChildElement("ServiceInvocationId",
+				mobyPrefix, MobyService.BIOMOBY_SERVICE_URI);
+		mobywsRoot.addNamespaceDeclaration(wsaPrefix, WSA_NS);
+		mobywsRoot.addAttribute(env.createName("isReferenceParameter",
+				wsaPrefix, WSA_NS), "true");
+		mobywsRoot.addTextNode(epr.getServiceInvocationId());
+
+		// At last, the replyto
+		SOAPElement replyRoot = header.addChildElement("ReplyTo", wsaPrefix,
+				WSA_NS);
+		replyRoot.addAttribute(env.createName("Id", wsuPrefix, WSU_NS),
+				"ReplyTo");
+		SOAPElement addr = replyRoot.addChildElement("Address", wsaPrefix,
+				WSA_NS);
+		addr.addTextNode(ANON_URI);
+
+		// Let's disable the headers
+		// ((WSBindingProvider)dispatch).setOutboundHeaders(headers);
+
+		// Now the SOAP body
+		SOAPElement smrp = body.addChildElement(
+				"GetMultipleResourceProperties", "rp", RESOURCE_PROPERTIES_NS);
+		boolean doSubmit = false;
+		for (String queryId : queryIds) {
+			if (queryId != null) {
+				doSubmit = true;
+				SOAPElement sii = smrp.addChildElement("ResourceProperty",
+						"rp", RESOURCE_PROPERTIES_NS);
+				sii.addNamespaceDeclaration(mobyPrefix,
+						MobyService.BIOMOBY_SERVICE_URI);
+				sii.addTextNode(mobyPrefix + ":" + op + queryId);
+			}
+		}
+
+		if (doSubmit) {
+			request.saveChanges();
+			SOAPMessage output = dispatch.invoke(request);
+
+			return output.getSOAPPart();
+		} else {
+			return null;
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteCgiService.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteCgiService.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteCgiService.java
new file mode 100644
index 0000000..a221a8a
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteCgiService.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+
+import org.biomoby.shared.MobyException;
+
+/**
+ * This class contains one method that is used to execute synchronous HTTP POST
+ * services
+ * 
+ * @author Edward Kawas
+ * 
+ */
+
+public class ExecuteCgiService {
+
+	/**
+	 * 
+	 * @param serviceEndpoint
+	 *            the URL to the HTTP POST service
+	 * @param xml
+	 *            the XML to send the service
+	 * @return a string representing the output from the service
+	 * @throws MobyException
+	 *             if anything goes wrong (problems reading/writing to the
+	 *             service)
+	 */
+	public static String executeCgiService(String serviceEndpoint, String xml)
+			throws MobyException {
+		try {
+			// Construct data
+			String data = "data=" + URLEncoder.encode(xml, "UTF-8");
+
+			// Send data
+			URL url = new URL(serviceEndpoint);
+			URLConnection conn = url.openConnection();
+			conn.setDoOutput(true);
+			OutputStreamWriter wr = new OutputStreamWriter(conn
+					.getOutputStream());
+			wr.write(data);
+			wr.flush();
+			// Get the response
+			BufferedReader rd = new BufferedReader(new InputStreamReader(conn
+					.getInputStream()));
+			String line;
+			StringBuffer sb = new StringBuffer();
+			while ((line = rd.readLine()) != null) {
+				sb.append(line);
+			}
+			wr.close();
+			rd.close();
+			return sb.toString();
+		} catch (Exception e) {
+			throw new MobyException(e.getMessage());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteMobyService.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteMobyService.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteMobyService.java
new file mode 100644
index 0000000..f494d47
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ExecuteMobyService.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import org.biomoby.client.CentralImpl;
+import org.biomoby.shared.MobyException;
+
+/**
+ * This class contains one method that is used to execute synchronous moby
+ * services
+ * 
+ * @author Edward Kawas
+ * 
+ */
+
+public class ExecuteMobyService {
+
+	/**
+	 * 
+	 * @param endpoint
+	 *            the SOAP endpoint of the service to call
+	 * @param service
+	 *            the name of the service
+	 * @param xml
+	 *            the XML to send the service
+	 * @return a string of XML representing the output from the service given
+	 *         our input
+	 * @throws MobyException
+	 *             if anything goes wrong (SOAP error)
+	 */
+	public static String executeMobyService(String endpoint, String service,
+			String xml) throws MobyException {
+		return new CentralImpl(endpoint, "http://biomoby.org/").call(service,
+				xml);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/GetOntologyThread.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/GetOntologyThread.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/GetOntologyThread.java
new file mode 100644
index 0000000..e2402e8
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/GetOntologyThread.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+/*
+ * This file is a component of the Taverna project,
+ * and is licensed under the GNU LGPL.
+ * Copyright Edward Kawas, The BioMoby Project
+ */
+
+package net.sf.taverna.t2.activities.biomoby;
+
+
+import org.biomoby.client.CentralImpl;
+
+/**
+ * This class is used to speed up the running of workflows. Basically, whenever
+ * a new Biomoby activity is added to taverna, a call out to RESOURCES/Objects
+ * is made to download the datatype ontology.
+ *
+ * Uses BiomobyCache to process the registry
+ * 
+ * This should speed up the execution of workflows, since the ontologies will
+ * have already been downloaded.
+ * 
+ * @author Eddie Kawas
+ * @author Stuart Owen
+ *
+ * @see BiomobyCache
+ * 
+ */
+public class GetOntologyThread extends Thread {
+
+	
+	// the registry endpoint
+	String worker = null;
+
+	/**
+	 * 
+	 * @param url
+	 *            the registry endpoint URL
+	 */
+	public GetOntologyThread(String url) {
+		super("BioMOBY GetOntologyThread");
+		if (url == null || url.trim().equals(""))
+			url = CentralImpl.getDefaultURL();
+		this.worker = url;
+		setDaemon(true);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Thread#run()
+	 */
+	public void run() {
+		BiomobyCache.cacheForRegistryEndpoint(worker);		
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivity.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivity.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivity.java
new file mode 100644
index 0000000..c33a5bf
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivity.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+
+import net.sf.taverna.t2.annotation.annotationbeans.MimeType;
+import net.sf.taverna.t2.reference.ExternalReferenceSPI;
+import net.sf.taverna.t2.reference.ReferenceService;
+import net.sf.taverna.t2.reference.ReferenceServiceException;
+import net.sf.taverna.t2.reference.T2Reference;
+import net.sf.taverna.t2.workflowmodel.EditException;
+import net.sf.taverna.t2.workflowmodel.OutputPort;
+import net.sf.taverna.t2.workflowmodel.processor.activity.AbstractAsynchronousActivity;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityConfigurationException;
+import net.sf.taverna.t2.workflowmodel.processor.activity.AsynchronousActivityCallback;
+
+import org.apache.log4j.Logger;
+import org.biomoby.client.CentralImpl;
+import org.biomoby.shared.Central;
+import org.biomoby.shared.MobyDataType;
+import org.biomoby.shared.MobyException;
+import org.biomoby.shared.MobyRelationship;
+import org.biomoby.shared.NoSuccessException;
+
+/**
+ * An Activity that breaks up a Moby datatype into its component parts minus all
+ * the moby wrappings.
+ *
+ * Copied from org.biomoby.client.taverna.plugin.MobyParseDatatypeActivityProcessor and
+ * org.biomoby.client.taverna.plugin.MobyParseDatatypeActivityTask and converted to a Taverna 2
+ * Activity.
+ *
+ * @author Edward Kawas
+ * @author David Withers
+ */
+public class MobyParseDatatypeActivity extends AbstractAsynchronousActivity<MobyParseDatatypeActivityConfigurationBean> {
+
+	public static final String URI = "http://ns.taverna.org.uk/2010/activity/biomoby/parser";
+
+	private static Logger logger = Logger.getLogger(MobyParseDatatypeActivity.class);
+
+	private MobyParseDatatypeActivityConfigurationBean configurationBean = new MobyParseDatatypeActivityConfigurationBean();
+
+	private Central central = null;
+
+	private MobyDataType datatype = null;
+
+	@Override
+	public void configure(MobyParseDatatypeActivityConfigurationBean configurationBean) throws ActivityConfigurationException {
+		this.configurationBean = configurationBean;
+		init();
+	}
+
+	@Override
+	public void executeAsynch(final Map<String, T2Reference> data,
+			final AsynchronousActivityCallback callback) {
+		callback.requestRun(new Runnable() {
+
+			@SuppressWarnings("unchecked")
+			public void run() {
+				ReferenceService referenceService = callback.getContext().getReferenceService();
+
+				Map<String, T2Reference> output = new HashMap<String, T2Reference>();
+
+				try {
+
+                    //cache ontology and namespace if not done so already. Immediately returns if already cached.
+                    BiomobyCache.cacheForRegistryEndpoint(getConfiguration().getRegistryEndpoint());
+
+					String inputMapKey = getInputPorts().iterator().next().getName();
+					// inputMap wasnt as expected
+					if (!data.containsKey(inputMapKey)) {
+						callback.receiveResult(output, new int[0]);
+						return;
+					}
+
+					T2Reference inputId = data.get(inputMapKey);
+
+					Object input = referenceService.renderIdentifier(inputId, String.class, callback.getContext());
+
+					if (input instanceof String) {
+						//logger.error(inputMapKey + " is a string!\n");
+						String inputXML = (String) input;
+						for (OutputPort outPort : getOutputPorts()) {
+							String outputPortName = outPort.getName();
+							String[] invocations = XMLUtilities.getSingleInvokationsFromMultipleInvokations(inputXML);
+							ArrayList<String> names = new ArrayList<String>();
+							int type = 0;
+							// get the type, names list, etc
+							if (outputPortName.equalsIgnoreCase("namespace")) {
+								// extract the namespace from the top element
+								names.add(configurationBean.getArticleNameUsedByService());
+								type = ParseMobyXML.NAMESPACE;
+							} else if (outputPortName.equalsIgnoreCase("id")) {
+								// extract the id from the top element
+								names.add(configurationBean.getArticleNameUsedByService());
+								type = ParseMobyXML.ID;
+							} else {
+								names = getNames(outputPortName);
+								if (outputPortName.endsWith("_ns")) {
+									type = ParseMobyXML.NAMESPACE;
+									if (names.size() > 1) // added nov15-2007
+										names.remove(names.size()-1);
+								} else if (outputPortName.endsWith("_id")) {
+									type = ParseMobyXML.ID;
+									if (names.size() > 1)//added nov15-2007
+		                                                                names.remove(names.size()-1);
+								} else {
+									type = ParseMobyXML.VALUE;
+								}
+							}
+							ArrayList<String> stuff = new ArrayList<String>();
+							for (int i = 0; i < invocations.length; i++) {
+								String invocation = invocations[i];
+								if (XMLUtilities.isCollection(invocation)) {
+									String[] simples = XMLUtilities.getAllSimplesByArticleName(configurationBean.getArticleNameUsedByService(), invocation);
+									for (int j = 0; j < simples.length; j++) {
+										ArrayList<String> content = ParseMobyXML.getContentForDataType(names, type, XMLUtilities.createMobyDataElementWrapper(simples[j],"a1", null), configurationBean.getRegistryEndpoint());
+										stuff.addAll(content);
+									}
+								} else {
+									ArrayList<String> content = ParseMobyXML.getContentForDataType(names, type, invocations[i],configurationBean.getRegistryEndpoint());
+									stuff.addAll(content);
+								}
+							}
+							output.put(outputPortName, referenceService.register(stuff, 1, true, callback.getContext()));
+						}
+
+					} else if (input instanceof List) {
+						//logger.error(inputMapKey + " is a list!\n");
+						List<String> list = (List) input;
+						// holder contains a list of strings indexed by output port name
+						// TODO put stuff in the map and in the end put it in the output map
+						HashMap<String, ArrayList<String>> holder = new HashMap<String, ArrayList<String>>();
+						for (Iterator<String> it = list.iterator(); it.hasNext();) {
+							String inputXML = (String) it.next();
+							for (OutputPort outPort : getOutputPorts()) {
+								String outputPortName = outPort.getName();
+								String[] invocations = XMLUtilities.getSingleInvokationsFromMultipleInvokations(inputXML);
+								ArrayList<String> names = new ArrayList<String>();
+								int type = 0;
+								// get the type, names list, etc
+								if (outputPortName.equalsIgnoreCase("namespace")) {
+									// extract the namespace from the top element
+									names.add(configurationBean.getArticleNameUsedByService());
+									type = ParseMobyXML.NAMESPACE;
+								} else if (outputPortName.equalsIgnoreCase("id")) {
+									// extract the id from the top element
+									names.add(configurationBean.getArticleNameUsedByService());
+									type = ParseMobyXML.ID;
+								} else {
+									names = getNames(outputPortName);
+									if (outputPortName.endsWith("_ns")) {
+										type = ParseMobyXML.NAMESPACE;
+										if (names.size() > 1)//added nov-15-07
+		                                                                	names.remove(names.size()-1);
+									} else if (outputPortName.endsWith("_id")) {
+										type = ParseMobyXML.ID;
+										if (names.size() > 1)//added nov-15-07
+		                                                                        names.remove(names.size()-1);
+									} else {
+										type = ParseMobyXML.VALUE;
+									}
+								}
+								ArrayList<String> stuff = new ArrayList<String>();
+								for (int i = 0; i < invocations.length; i++) {
+									String invocation = invocations[i];
+									if (XMLUtilities.isCollection(invocation)) {
+										String[] simples = XMLUtilities.getAllSimplesByArticleName(configurationBean.getArticleNameUsedByService(), invocation);
+										for (int j = 0; j < simples.length; j++) {
+											ArrayList<String> content = ParseMobyXML.getContentForDataType(names, type, XMLUtilities.createMobyDataElementWrapper(simples[j],"a1", null),configurationBean.getRegistryEndpoint());
+											stuff.addAll(content);
+										}
+									} else {
+										ArrayList<String> content = ParseMobyXML.getContentForDataType(names, type, invocations[i],configurationBean.getRegistryEndpoint());
+										stuff.addAll(content);
+									}
+								}
+								if (holder.containsKey(outputPortName)) {
+									ArrayList<String> al = holder.get(outputPortName);
+									al.addAll(stuff);
+									holder.put(outputPortName, al);
+								} else {
+									holder.put(outputPortName, stuff);
+								}
+							}
+						}
+						// fill output map
+						for (Iterator<String> it = holder.keySet().iterator(); it.hasNext();) {
+							String key = it.next();
+							output.put(key, referenceService.register(holder.get(key), 1, true, callback.getContext()));
+						}
+					}
+
+					callback.receiveResult(output, new int[0]);
+				} catch (ReferenceServiceException e) {
+					callback.fail("Error accessing input/output data", e);
+				} catch (Exception e) {
+					callback.fail("rror parsing moby data", e);
+				}
+
+			}
+		});
+	}
+
+	@Override
+	public MobyParseDatatypeActivityConfigurationBean getConfiguration() {
+		return configurationBean;
+	}
+
+	@SuppressWarnings("unchecked")
+	private void init() throws ActivityConfigurationException {
+		try {
+			central = new CentralImpl(configurationBean.getRegistryEndpoint());
+		} catch (MobyException e) {
+			throw new ActivityConfigurationException("Couldn't create MobyCentral client for endpoint "
+					+ configurationBean.getRegistryEndpoint() + System.getProperty("line.separator")
+					+ e.getLocalizedMessage());
+		}
+		if (this.datatype == null) {
+			try {
+				this.datatype = central.getDataType(configurationBean.getDatatypeName());
+			} catch (MobyException e) {
+				throw new ActivityConfigurationException(
+						"There was a problem getting information from the MobyCentral registry at "
+								+ configurationBean.getRegistryEndpoint() + System.getProperty("line.separator")
+								+ e.getLocalizedMessage());
+			} catch (NoSuccessException e) {
+				throw new ActivityConfigurationException(
+						"There was no success in getting information from the MobyCentral registry at "
+								+ configurationBean.getRegistryEndpoint() + System.getProperty("line.separator")
+								+ e.getLocalizedMessage());
+			}
+		}
+
+//		setDescription("Service to parse the datatype " + this.datatype.getName());
+
+		ArrayList list = new ArrayList();
+		if (isPrimitive(this.datatype.getName())) {
+			list.add(configurationBean.getArticleNameUsedByService() + "_" + this.datatype.getName());
+		} else if (this.datatype.getName().equals("Object")) {
+			// dont do anything because object has no value
+		} else {
+			processDatatype(this.datatype, central, configurationBean.getArticleNameUsedByService(), list);
+		}
+		// add the input port called mobyData('datatypeName')
+		addInput("mobyData('" + this.datatype.getName() + "')", 0, true,
+				new ArrayList<Class<? extends ExternalReferenceSPI>>(),
+				String.class);
+		// add the namespace/id ports to the processor
+		addOutput("namespace", 1, "text/xml");
+		addOutput("id", 1, "text/xml");
+
+		// list contains the output ports i have to create
+		for (Iterator it = list.iterator(); it.hasNext();) {
+			String portName = (String) it.next();
+			if (portName.equals(configurationBean.getArticleNameUsedByService()+"_id") || portName.equals(configurationBean.getArticleNameUsedByService()+"_ns"))
+				continue;
+			addOutput(portName, 1, "text/xml");
+		}
+	}
+
+	private boolean isPrimitive(String name) {
+		if (name.equals("Integer") || name.equals("String") || name.equals("Float")
+				|| name.equals("DateTime") || name.equals("Boolean")
+		)
+			return true;
+		return false;
+	}
+
+	@SuppressWarnings("unchecked")
+	private void processDatatype(MobyDataType dt, Central central, String currentName, List list) throws ActivityConfigurationException {
+
+		if (dt.getParentName() == null || dt.getParentName().trim().equals("")) {
+			//TODO should we throw an error or just return ...
+			return;
+		}
+
+		if (!dt.getParentName().equals("Object")) {
+			flattenChildType(dt.getParentName(), central, currentName, list);
+		} else {
+			list.add(currentName + "_id");
+			list.add(currentName + "_ns");
+		}
+
+		MobyRelationship[] relations = dt.getChildren();
+		for (int i = 0; i < relations.length; i++) {
+			MobyRelationship relation = relations[i];
+			switch (relation.getRelationshipType()) {
+			case CentralImpl.iHAS: {
+				// check for object or primitives
+				if (isPrimitive(relation.getDataTypeName()) || relation.getDataTypeName().equals("Object")) {
+					// object has no value ... only primitives do
+					if (!relation.getDataTypeName().equals("Object"))
+						list.add(currentName + (currentName.equals("") ? "" : "_'")
+								+ relation.getName() + (currentName.equals("") ? "" : "'"));
+					list.add(currentName + (currentName.equals("") ? "" : "_'")
+							+ relation.getName() + (currentName.equals("") ? "" : "'")+"_id");
+					list.add(currentName + (currentName.equals("") ? "" : "_'")
+							+ relation.getName() + (currentName.equals("") ? "" : "'")+"_ns");
+				}
+				else {
+					flattenChildType(relation.getDataTypeName(), central, currentName
+							+ (currentName.equals("") ? "" : "_'") + relation.getName() + (currentName.equals("") ? "" : "'"), list);
+				}
+			}
+			break;
+			case CentralImpl.iHASA: {
+				// check for object or primitives ...
+				if (isPrimitive(relation.getDataTypeName()) || relation.getDataTypeName().equals("Object")) {
+					// object has no value ... only primitives do
+					if (!relation.getDataTypeName().equals("Object"))
+						list.add(currentName + (currentName.equals("") ? "" : "_'")
+								+ relation.getName()+ (currentName.equals("") ? "" : "'"));
+					list.add(currentName + (currentName.equals("") ? "" : "_'")
+							+ relation.getName() + (currentName.equals("") ? "" : "'")+"_id");
+					list.add(currentName + (currentName.equals("") ? "" : "_'")
+							+ relation.getName() + (currentName.equals("") ? "" : "'")+"_ns");
+				}
+				else {
+
+					flattenChildType(relation.getDataTypeName(), central, currentName
+							+ (currentName.equals("") ? "" : "_'") + relation.getName() + (currentName.equals("") ? "" : "'"), list);
+				}
+			}
+			break;
+			default:
+				break;
+			}
+		}
+
+	}
+
+	@SuppressWarnings("unchecked")
+	private void flattenChildType(String name, Central central, String current, List list) throws ActivityConfigurationException {
+		MobyDataType dt = null;
+		try {
+			dt = central.getDataType(name);
+		} catch (MobyException e) {
+			throw new ActivityConfigurationException(
+					"There was a problem getting information from the MobyCentral registry at "
+					+ configurationBean.getRegistryEndpoint() + System.getProperty("line.separator")
+					+ e.getLocalizedMessage());
+		} catch (NoSuccessException e) {
+			throw new ActivityConfigurationException(
+					"There was no success in getting information from the MobyCentral registry at "
+					+ configurationBean.getRegistryEndpoint() + System.getProperty("line.separator")
+					+ e.getLocalizedMessage());
+		}
+		processDatatype(dt, central, current, list);
+	}
+
+	private ArrayList<String> getNames(String names) {
+		ArrayList<String> list = new ArrayList<String>();
+		ArrayList<String> temp = new ArrayList<String>();
+		if (names == null || names.trim().length() == 0)
+			return list;
+		Scanner s = new Scanner(names).useDelimiter("_'");
+		while (s.hasNext()) {
+			temp.add(s.next());
+		}
+		s.close();
+
+		for (String str : temp) {
+			if (str.indexOf("'_") >= 0) {
+				String[] strings = str.split("'_");
+				for (int i = 0; i < strings.length; i++) {
+					list.add(strings[i].replaceAll("'", ""));
+				}
+			} else {
+				list.add(str.replaceAll("'", ""));
+			}
+		}
+
+		if (list.size() == 1) {
+			if (endsWithPrimitive(list.get(0))) {
+				String name = list.remove(0);
+				int i = name.lastIndexOf("_");
+				name = name.substring(0, i);
+				list.add(name);
+			}
+		} else if (isPrimitive(list.get(list.size()-1))) {
+			// remove the last entry if its a primitive ... legacy reasons
+			list.remove(list.size()-1);
+		}
+		return list;
+	}
+
+	private static boolean endsWithPrimitive(String name) {
+		if (name.endsWith("_Integer") || name.endsWith("_String") || name.endsWith("_Float")
+				|| name.endsWith("_DateTime") || name.endsWith("_Boolean"))
+			return true;
+		return false;
+	}
+
+	protected void addOutput(String portName, int portDepth, String type) {
+		OutputPort port = edits.createActivityOutputPort(
+				portName, portDepth, portDepth);
+		MimeType mimeType = new MimeType();
+		mimeType.setText(type);
+		try {
+			edits.getAddAnnotationChainEdit(port, mimeType).doEdit();
+		} catch (EditException e) {
+			logger.debug("Error adding MimeType annotation to port", e);
+		}
+		outputPorts.add(port);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityConfigurationBean.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityConfigurationBean.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityConfigurationBean.java
new file mode 100644
index 0000000..1f02e7e
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityConfigurationBean.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationBean;
+import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationProperty;
+
+/**
+ * A configuration bean specific to the Moby Parse Datatype activity.
+ * 
+ * @author David Withers
+ */
+@ConfigurationBean(uri = MobyParseDatatypeActivity.URI + "#Config")
+public class MobyParseDatatypeActivityConfigurationBean {
+
+	private String datatypeName="";
+
+	private String registryEndpoint="";
+	
+	private String articleNameUsedByService="";
+
+	/**
+	 * Returns the datatypeName.
+	 *
+	 * @return the datatypeName
+	 */
+	public String getDatatypeName() {
+		return datatypeName;
+	}
+
+	/**
+	 * Sets the datatypeName.
+	 *
+	 * @param datatypeName the new datatypeName
+	 */
+	@ConfigurationProperty(name = "datatypeName", label = "Datatype Name", description = "")
+	public void setDatatypeName(String datatypeName) {
+		this.datatypeName = datatypeName;
+	}
+
+	/**
+	 * Returns the registryEndpoint.
+	 *
+	 * @return the registryEndpoint
+	 */
+	public String getRegistryEndpoint() {
+		return registryEndpoint;
+	}
+
+	/**
+	 * Sets the registryEndpoint.
+	 *
+	 * @param registryEndpoint the new registryEndpoint
+	 */
+	@ConfigurationProperty(name = "registryEndpoint", label = "Registry Endpoint", description = "")
+	public void setRegistryEndpoint(String registryEndpoint) {
+		this.registryEndpoint = registryEndpoint;
+	}
+
+	/**
+	 * Returns the articleNameUsedByService.
+	 *
+	 * @return the articleNameUsedByService
+	 */
+	public String getArticleNameUsedByService() {
+		return articleNameUsedByService;
+	}
+
+	/**
+	 * Sets the articleNameUsedByService.
+	 *
+	 * @param articleNameUsedByService the new articleNameUsedByService
+	 */
+	@ConfigurationProperty(name = "articleNameUsedByService", label = "Article Name Used By Service", description = "")
+	public void setArticleNameUsedByService(String articleNameUsedByService) {
+		this.articleNameUsedByService = articleNameUsedByService;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityFactory.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityFactory.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityFactory.java
new file mode 100644
index 0000000..8da531e
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityFactory.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (C) 2011 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.activities.biomoby;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityFactory;
+
+/**
+ * An {@link ActivityFactory} for creating <code>MobyParseDatatypeActivity</code>.
+ * 
+ * @author David Withers
+ */
+public class MobyParseDatatypeActivityFactory implements ActivityFactory {
+
+	@Override
+	public MobyParseDatatypeActivity createActivity() {
+		return new MobyParseDatatypeActivity();
+	}
+
+	@Override
+	public URI getActivityURI() {
+		return URI.create(MobyParseDatatypeActivity.URI);
+	}
+
+	@Override
+	public Object createActivityConfiguration() {
+		return new MobyParseDatatypeActivityConfigurationBean();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityHealthChecker.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityHealthChecker.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityHealthChecker.java
new file mode 100644
index 0000000..0ca0d38
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/MobyParseDatatypeActivityHealthChecker.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * This file is a component of the Taverna project, and is licensed  under the
+ *  GNU LGPL. Copyright Edward Kawas, The BioMoby Project
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.List;
+
+import net.sf.taverna.t2.workflowmodel.Processor;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import net.sf.taverna.t2.workflowmodel.health.HealthCheck;
+import net.sf.taverna.t2.workflowmodel.health.HealthChecker;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.visit.VisitReport.Status;
+
+import net.sf.taverna.t2.workflowmodel.health.RemoteHealthChecker;
+import net.sf.taverna.t2.workflowmodel.processor.activity.DisabledActivity;
+
+
+/**
+ * A health checker for the Moby Parse Datatype activity.
+ * 
+ * @author David Withers
+ */
+public class MobyParseDatatypeActivityHealthChecker extends RemoteHealthChecker {
+
+	
+	public boolean canVisit(Object subject) {
+		if (subject == null) {
+			return false;
+		}
+		if (subject instanceof MobyParseDatatypeActivity) {
+			return true;
+		}
+		if (subject instanceof DisabledActivity) {
+			return (((DisabledActivity) subject).getActivity() instanceof MobyParseDatatypeActivity);
+		}
+		return false;
+	}
+
+	public VisitReport visit(Object o, List<Object> ancestors) {
+		Activity activity = (Activity) o;
+		MobyParseDatatypeActivityConfigurationBean configuration = null;
+		if (activity instanceof MobyParseDatatypeActivity) {
+			configuration = (MobyParseDatatypeActivityConfigurationBean) activity.getConfiguration();
+		} else if (activity instanceof DisabledActivity) {
+			configuration = (MobyParseDatatypeActivityConfigurationBean) ((DisabledActivity) activity).getActivityConfiguration();
+		}
+		return contactEndpoint(activity, configuration.getRegistryEndpoint());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-plugin-bioinformatics/blob/a87b4151/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ParseMobyXML.java
----------------------------------------------------------------------
diff --git a/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ParseMobyXML.java b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ParseMobyXML.java
new file mode 100644
index 0000000..042b6e8
--- /dev/null
+++ b/taverna-biomoby-activity/src/main/java/net/sf/taverna/t2/activities/biomoby/ParseMobyXML.java
@@ -0,0 +1,192 @@
+/*
+ * This file is a component of the Taverna project,
+ * and is licensed under the GNU LGPL.
+ * Copyright Edward Kawas, The BioMoby Project
+ */
+package net.sf.taverna.t2.activities.biomoby;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.biomoby.shared.MobyNamespace;
+import org.biomoby.shared.data.MobyContentInstance;
+import org.biomoby.shared.data.MobyDataBoolean;
+import org.biomoby.shared.data.MobyDataComposite;
+import org.biomoby.shared.data.MobyDataFloat;
+import org.biomoby.shared.data.MobyDataInstance;
+import org.biomoby.shared.data.MobyDataInt;
+import org.biomoby.shared.data.MobyDataJob;
+import org.biomoby.shared.data.MobyDataObject;
+import org.biomoby.shared.data.MobyDataObjectVector;
+import org.biomoby.shared.data.MobyDataString;
+import org.biomoby.shared.data.MobyDataUtils;
+import org.biomoby.registry.meta.Registry;
+
+/**
+ * This class is used to help parse BioMOBY messages.
+ * 
+ * @author Edward Kawas
+ * 
+ */
+public class ParseMobyXML {
+
+    private static Logger logger = Logger.getLogger(ParseMobyXML.class);
+
+    public static final int NAMESPACE = -10;
+
+    public static final int ID = -20;
+
+    public static final int VALUE = -30;
+
+    private static final List<Integer> allowables;
+
+    static {
+	allowables = new ArrayList<Integer>();
+	allowables.add(NAMESPACE);
+	allowables.add(ID);
+	allowables.add(VALUE);
+    }
+
+    /**
+     * PRECONDITION: XML is valid MOBY xml and contains exactly 1 invocation
+     * message containing our simple element
+     * 
+     * @param names
+     *                an array of article names in the order that we will
+     *                extract our information
+     * @param type
+     *                one of {NAMESPACE | ID | VALUE} denoting what exactly it
+     *                is that you would like returned
+     * @param xml
+     *                the MOBY xml containing the data to extract
+     * @param endpoint
+     *                the BioMOBY registry endpoint to use
+     * @return a list of strings representing what it is you asked for
+     */
+    public static ArrayList<String> getContentForDataType(
+	    ArrayList<String> names, int type, String xml, String endpoint) {
+	if (!allowables.contains(type) || names == null || names.size() == 0
+		|| xml == null || xml.trim().length() == 0) {
+	    // nothing to return
+	    logger.warn("Parser invoked on an empty message ...");
+	    return new ArrayList<String>();
+	}
+	MobyContentInstance contents;
+	try {
+	    contents = MobyDataUtils.fromXMLDocument(new ByteArrayInputStream(
+		    xml.getBytes("UTF8")), new Registry(endpoint, endpoint,
+		    "http://domain.com/MOBY/Central"));
+	} catch (Exception e) {
+	    logger.error("There was a problem parsing the input XML:\n" + xml
+		    + "\n", e);
+	    return new ArrayList<String>();
+	}
+	if (contents.keySet().size() != 1) {
+	    return new ArrayList<String>();
+	}
+
+	ArrayList<String> clone = new ArrayList<String>();
+	clone.addAll(names);
+	ArrayList<String> output = new ArrayList<String>();
+	// should be exactly 1 job!
+	Iterator<String> jobIDs = contents.keySet().iterator();
+	while (jobIDs.hasNext()) {
+	    MobyDataJob job = (MobyDataJob) contents.get(jobIDs.next());
+	    // get the instance
+	    MobyDataInstance data = job.get(clone.remove(0));
+	    if (data == null)
+		return output;
+	    recurse(clone, data, output, type);
+	}
+	return output;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void recurse(ArrayList<String> names, MobyDataInstance data,
+	    ArrayList<String> output, int type) {
+	// base case => we have finally found the element of interest
+	if (names.isEmpty()) {
+	    baseCase(data, output, type);
+	    return;
+	}
+	if (data instanceof MobyDataObjectVector) {
+	    // recurse on the children -- the recursion will extract by
+	    // articlename
+	    MobyDataObjectVector vector = (MobyDataObjectVector) data;
+	    // recurse on the has relationship
+	    for (Iterator i = vector.iterator(); i.hasNext();) {
+		recurse((ArrayList) (names.clone()), (MobyDataInstance) i
+			.next(), output, type);
+	    }
+
+	} else if (data instanceof MobyDataComposite) {
+	    // recurse on the child given by name.get(0)
+	    MobyDataInstance d = ((MobyDataComposite) data).remove(names
+		    .remove(0));
+	    recurse((ArrayList) (names.clone()), d, output, type);
+	} else if (data instanceof MobyDataBoolean) {
+	    baseCase(data, output, type);
+	} else if (data instanceof MobyDataFloat) {
+	    baseCase(data, output, type);
+	} else if (data instanceof MobyDataInt) {
+	    baseCase(data, output, type);
+	} else if (data instanceof MobyDataString) {
+	    baseCase(data, output, type);
+	}
+
+    }
+
+    private static void baseCase(MobyDataInstance data,
+	    ArrayList<String> output, int type) {
+	if (data == null)
+	    return;
+	switch (type) {
+	case NAMESPACE: {
+	    if (data instanceof MobyDataObjectVector) {
+		MobyDataObjectVector vector = (MobyDataObjectVector) data;
+		for (Iterator i = vector.iterator(); i.hasNext();) {
+		    MobyNamespace[] namespaces = ((MobyDataObject) i.next())
+			    .getNamespaces();
+		    for (int j = 0; j < namespaces.length; j++) {
+			output.add(namespaces[j].getName());
+		    }
+		}
+	    } else {
+		MobyNamespace[] namespaces = ((MobyDataObject) data)
+			.getNamespaces();
+		for (int j = 0; j < namespaces.length; j++) {
+		    output.add(namespaces[j].getName());
+		}
+	    }
+	}
+	    break;
+	case ID: {
+	    if (data instanceof MobyDataObjectVector) {
+		MobyDataObjectVector vector = (MobyDataObjectVector) data;
+		for (Iterator i = vector.iterator(); i.hasNext();) {
+		    output.add(((MobyDataObject) i.next()).getId());
+		}
+	    } else {
+		output.add(((MobyDataObject) data).getId());
+	    }
+	}
+	    break;
+	case VALUE: {
+	    if (data instanceof MobyDataObjectVector) {
+		MobyDataObjectVector vector = (MobyDataObjectVector) data;
+		for (Iterator i = vector.iterator(); i.hasNext();) {
+		    output.add(((MobyDataObject) i.next()).getValue());
+		}
+	    } else {
+		output.add(((MobyDataObject) data).getValue());
+	    }
+	}
+	    break;
+	default:
+	    break;
+	}
+    }
+}