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/17 12:37:13 UTC

[53/70] [abbrv] incubator-taverna-common-activities git commit: taverna-xpath-activity/

taverna-xpath-activity/


Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/commit/d2da8c61
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/tree/d2da8c61
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/diff/d2da8c61

Branch: refs/heads/master
Commit: d2da8c61ff34424664d6d03425d4ad7f3512734a
Parents: 1cc909e
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Thu Jan 29 09:35:50 2015 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Thu Jan 29 09:35:50 2015 +0000

----------------------------------------------------------------------
 .gitignore                                      |  24 ---
 .travis.yml                                     |   1 -
 README.md                                       |   3 -
 pom.xml                                         |  78 -------
 .../t2/activities/xpath/XPathActivity.java      | 211 -------------------
 .../xpath/XPathActivityConfigurationBean.java   | 145 -------------
 .../activities/xpath/XPathActivityFactory.java  |  92 --------
 .../xpath/XPathActivityHealthCheck.java         |  38 ----
 .../xpath/XPathActivityHealthChecker.java       | 139 ------------
 .../taverna/t2/activities/xpath/XPathUtils.java |  80 -------
 ...t2.workbench.report.explainer.VisitExplainer |   1 -
 ...averna.t2.workflowmodel.health.HealthChecker |   1 -
 .../spring/xpath-activity-context-osgi.xml      |  15 --
 .../META-INF/spring/xpath-activity-context.xml  |  12 --
 src/main/resources/schema.json                  |  45 ----
 taverna-xpath-activity/pom.xml                  |  78 +++++++
 .../t2/activities/xpath/XPathActivity.java      | 211 +++++++++++++++++++
 .../xpath/XPathActivityConfigurationBean.java   | 145 +++++++++++++
 .../activities/xpath/XPathActivityFactory.java  |  92 ++++++++
 .../xpath/XPathActivityHealthCheck.java         |  38 ++++
 .../xpath/XPathActivityHealthChecker.java       | 139 ++++++++++++
 .../taverna/t2/activities/xpath/XPathUtils.java |  80 +++++++
 ...t2.workbench.report.explainer.VisitExplainer |   1 +
 ...averna.t2.workflowmodel.health.HealthChecker |   1 +
 .../spring/xpath-activity-context-osgi.xml      |  15 ++
 .../META-INF/spring/xpath-activity-context.xml  |  12 ++
 .../src/main/resources/schema.json              |  45 ++++
 27 files changed, 857 insertions(+), 885 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index ebe0e5b..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# ignore project files #
-.classpath
-.project
-.settings/
-catalog-v001.xml
-
-# ignore target files #
-target/
-bin/
-build/
-dist/
-apidoc/
-*.swp
-
-# ignore svn files if there
-.svn
-
-# ignore log files #
-*.log
-/logs/*
-*/logs/*
-
-
-

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index dff5f3a..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1 +0,0 @@
-language: java

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
deleted file mode 100644
index 624f76f..0000000
--- a/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Taverna Workflow system XPath Activity: data model and execution implementation
-
-This code was previously hosted at http://taverna.googlecode.com/svn/taverna/engine/net.sf.taverna.t2.activities/

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index ecf89fa..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<parent>
-		<groupId>net.sf.taverna</groupId>
-		<artifactId>taverna-parent</artifactId>
-		<version>3.0.1-SNAPSHOT</version>
-	</parent>
-	<groupId>net.sf.taverna.t2.activities</groupId>
-	<artifactId>xpath-activity</artifactId>
-	<version>2.0.1-SNAPSHOT</version>
-	<name>Taverna XPath Activity</name>
-	<packaging>bundle</packaging>
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.felix</groupId>
-				<artifactId>maven-bundle-plugin</artifactId>
-				<extensions>true</extensions>
-				<configuration>
-					<instructions>
-						<Import-Package>org.jaxen,*</Import-Package>
-					</instructions>
-				</configuration>
-			</plugin>
-		</plugins>
-	</build>
-	<repositories>
-		<repository>
-			<releases />
-			<snapshots>
-				<enabled>false</enabled>
-			</snapshots>
-			<id>mygrid-repository</id>
-			<name>myGrid Repository</name>
-			<url>http://www.mygrid.org.uk/maven/repository</url>
-		</repository>
-		<repository>
-			<releases>
-				<enabled>false</enabled>
-			</releases>
-			<snapshots />
-			<id>mygrid-snapshot-repository</id>
-			<name>myGrid Snapshot Repository</name>
-			<url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
-		</repository>
-	</repositories>
-	<scm>
-		<connection>scm:git:https://github.com/taverna/taverna-xpath-activity.git</connection>
-		<developerConnection>scm:git:ssh://git@github.com/taverna/taverna-xpath-activity.git</developerConnection>
-		<url>https://github.com/taverna/taverna-xpath-activity/</url>
-		<tag>master</tag>
-	</scm>
-
-	<dependencies>
-		<dependency>
-			<groupId>net.sf.taverna.t2.core</groupId>
-			<artifactId>reference-api</artifactId>
-			<version>${t2.core.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>net.sf.taverna.t2.core</groupId>
-			<artifactId>workflowmodel-api</artifactId>
-			<version>${t2.core.version}</version>
-		</dependency>
-
-		<dependency>
-			<groupId>org.dom4j</groupId>
-			<artifactId>com.springsource.org.dom4j</artifactId>
-			<version>${dom4j.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.jaxen</groupId>
-			<artifactId>com.springsource.org.jaxen</artifactId>
-			<version>${jaxen.version}</version>
-		</dependency>
-	</dependencies>
-</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
deleted file mode 100644
index 260eb5a..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package net.sf.taverna.t2.activities.xpath;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.sf.taverna.t2.invocation.InvocationContext;
-import net.sf.taverna.t2.reference.ErrorDocumentService;
-import net.sf.taverna.t2.reference.ReferenceService;
-import net.sf.taverna.t2.reference.T2Reference;
-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.dom4j.Document;
-import org.dom4j.DocumentException;
-import org.dom4j.DocumentHelper;
-import org.dom4j.InvalidXPathException;
-import org.dom4j.Node;
-import org.dom4j.XPath;
-import org.dom4j.XPathException;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-/**
- * Enhanced XPath activity.
- *
- * @author Sergejs Aleksejevs
- */
-public class XPathActivity extends AbstractAsynchronousActivity<JsonNode> {
-
-	public static final String URI = "http://ns.taverna.org.uk/2010/activity/xpath";
-
-	// These ports are default ones (and only ones - XPath activity will not have dynamic ports)
-	public static final String IN_XML = "xml_text";
-	public static final String OUT_TEXT = "nodelist";
-	public static final String OUT_XML = "nodelistAsXML";
-
-	private static final String SINGLE_VALUE_TEXT = "firstNode";
-	private static final String SINGLE_VALUE_XML = "firstNodeAsXML";
-	
-	// Configuration bean for this activity - essentially defines a particular instance
-	// of the activity through the values of its parameters
-	private JsonNode json;
-
-	@Override
-	public JsonNode getConfiguration() {
-		return this.json;
-	}
-
-	@Override
-	public void configure(JsonNode json) throws ActivityConfigurationException {
-		// Check configBean is valid
-		if (!XPathUtils.isValid(json)) {
-			throw new ActivityConfigurationException("Invalid configuration of XPath activity...");
-			// TODO - check this
-		}
-
-		// Store for getConfiguration()
-		this.json = json;
-	}
-
-	protected void configurePorts() {
-		// ---- REMOVE OLD PORTS ----
-	  
-		// In case we are being reconfigured - remove existing ports first to avoid duplicates
-		removeInputs();
-		removeOutputs();
-
-		// ---- CREATE NEW INPUTS AND OUTPUTS ----
-		
-		// all ports in this activity are static, so no dependency on the values in config bean
-		
-		// single input port: the input XML text will be treated as String for now
-		addInput(IN_XML, 0, true, null, String.class);
-
-		addOutput(SINGLE_VALUE_TEXT, 0);
-		addOutput(SINGLE_VALUE_XML, 0);
-		addOutput(OUT_TEXT, 1);
-		addOutput(OUT_XML, 1);
-	}
-
-	/**
-	 * This method executes pre-configured instance of XPath activity.
-	 */
-	@Override
-	public void executeAsynch(final Map<String, T2Reference> inputs,
-			final AsynchronousActivityCallback callback) {
-		// Don't execute service directly now, request to be run asynchronously
-		callback.requestRun(new Runnable() {
-			@Override
-			@SuppressWarnings("unchecked")
-			public void run() {
-
-				InvocationContext context = callback.getContext();
-				ReferenceService referenceService = context.getReferenceService();
-
-				// ---- RESOLVE INPUT ----
-
-				String xmlInput = (String) referenceService.renderIdentifier(inputs.get(IN_XML),
-						String.class, context);
-
-				// ---- DO THE ACTUAL SERVICE INVOCATION ----
-
-				List<Node> matchingNodes = new ArrayList<Node>();
-
-				// only attempt to execute XPath expression if there is some input data
-				if (xmlInput != null && xmlInput.length() > 0) {
-					// XPath configuration is taken from the config bean
-					try {
-						XPath expr = DocumentHelper.createXPath(json.get("xpathExpression").textValue());
-						Map<String, String> xpathNamespaceMap = new HashMap<>();
-						for (JsonNode namespaceMapping : json.get("xpathNamespaceMap")) {
-							xpathNamespaceMap.put(namespaceMapping.get("prefix").textValue(),
-									namespaceMapping.get("uri").textValue());
-						}
-						expr.setNamespaceURIs(xpathNamespaceMap);
-						Document doc = DocumentHelper.parseText(xmlInput);
-						matchingNodes = expr.selectNodes(doc);
-					} catch (InvalidXPathException e) {
-						callback.fail("Incorrect XPath Expression -- XPath processing library "
-								+ "reported the following error: " + e.getMessage(), e);
-
-						// make sure we don't call callback.receiveResult later
-						return;
-					} catch (DocumentException e) {
-						callback.fail("XML document was not valid -- XPath processing library "
-								+ "reported the following error: " + e.getMessage(), e);
-
-						// make sure we don't call callback.receiveResult later
-						return;
-					} catch (XPathException e) {
-						callback.fail(
-								"Unexpected error has occurred while executing the XPath expression. "
-										+ "-- XPath processing library reported the following error:\n"
-										+ e.getMessage(), e);
-
-						// make sure we don't call callback.receiveResult later
-						return;
-					}
-				}
-				
-				// --- PREPARE OUTPUTS ---
-
-				List<String> outNodesText = new ArrayList<String>();
-				List<String> outNodesXML = new ArrayList<String>();
-				Object textValue = null;
-				Object xmlValue = null;
-
-				for (Object o : matchingNodes) {
-					if (o instanceof Node) {
-						Node n = (Node) o;
-						if (n.getStringValue() != null
-								&& n.getStringValue().length() > 0) {
-							outNodesText.add(n.getStringValue());
-							if (textValue == null)
-								textValue = n.getStringValue();
-						}
-						outNodesXML.add(n.asXML());
-						if (xmlValue == null)
-							xmlValue = n.asXML();
-					} else {
-						outNodesText.add(o.toString());
-						if (textValue == null)
-							textValue = o.toString();
-					}
-				}
-
-				// ---- REGISTER OUTPUTS ----
-
-				Map<String, T2Reference> outputs = new HashMap<String, T2Reference>();
-				if (textValue == null) {
-					ErrorDocumentService errorDocService = referenceService
-							.getErrorDocumentService();
-					textValue = errorDocService.registerError(
-							"No value produced", 0, callback.getContext());
-				}
-
-				if (xmlValue == null) {
-					ErrorDocumentService errorDocService = referenceService
-							.getErrorDocumentService();
-					xmlValue = errorDocService.registerError(
-							"No value produced", 0, callback.getContext());
-				}
-
-				T2Reference firstNodeAsText = referenceService.register(
-						textValue, 0, true, context);
-				outputs.put(SINGLE_VALUE_TEXT, firstNodeAsText);
-
-				T2Reference firstNodeAsXml = referenceService.register(
-						xmlValue, 0, true, context);
-				outputs.put(SINGLE_VALUE_XML, firstNodeAsXml);
-
-				T2Reference outNodesAsText = referenceService.register(
-						outNodesText, 1, true, context);
-				outputs.put(OUT_TEXT, outNodesAsText);
-
-				T2Reference outNodesAsXML = referenceService.register(
-						outNodesXML, 1, true, context);
-				outputs.put(OUT_XML, outNodesAsXML);
-
-				// return map of output data, with empty index array as this is
-				// the only and final result (this index parameter is used if
-				// pipelining output)
-				callback.receiveResult(outputs, new int[0]);
-			}
-		});
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
deleted file mode 100644
index 12bd536..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package net.sf.taverna.t2.activities.xpath;
-
-import static net.sf.taverna.t2.activities.xpath.XPathActivity.URI;
-import static org.dom4j.DocumentHelper.createXPath;
-
-import java.io.Serializable;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationBean;
-import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationProperty;
-
-import org.dom4j.DocumentException;
-import org.dom4j.InvalidXPathException;
-
-/**
- *
- * @author Sergejs Aleksejevs
- */
-@ConfigurationBean(uri = URI + "#Config")
-public class XPathActivityConfigurationBean implements Serializable {
-	// --- CONSTANTS ---
-	public static final int XPATH_VALID = XPathUtils.XPATH_VALID;
-	public static final int XPATH_EMPTY = XPathUtils.XPATH_EMPTY;
-	public static final int XPATH_INVALID = XPathUtils.XPATH_INVALID;
-
-	private String xmlDocument;
-	private String xpathExpression;
-	private Map<String, String> xpathNamespaceMap;
-
-	/**
-	 * @return An instance of the {@link XPathActivityConfigurationBean}
-	 *         pre-configured with default settings for all parameters.
-	 * @throws DocumentException
-	 */
-	public static XPathActivityConfigurationBean getDefaultInstance() {
-		// document will not be set
-		XPathActivityConfigurationBean defaultBean = new XPathActivityConfigurationBean();
-		defaultBean.setXpathExpression("/");
-		defaultBean.setXpathNamespaceMap(new HashMap<String, String>(0));
-
-		return (defaultBean);
-	}
-
-	/**
-	 * Validates an XPath expression.
-	 *
-	 * @return {@link XPathActivityConfigurationBean#XPATH_VALID XPATH_VALID} -
-	 *         if the expression is valid;<br/>
-	 *         {@link XPathActivityConfigurationBean#XPATH_EMPTY XPATH_EMPTY} -
-	 *         if expression is empty;<br/>
-	 *         {@link XPathActivityConfigurationBean#XPATH_INVALID
-	 *         XPATH_INVALID} - if the expression is invalid / ill-formed.<br/>
-	 */
-	public static int validateXPath(String xpathExpressionToValidate) {
-		// no XPath expression
-		if (xpathExpressionToValidate == null
-				|| xpathExpressionToValidate.trim().isEmpty()) {
-			return XPATH_EMPTY;
-		}
-
-		try {
-			// try to parse the XPath expression...
-			createXPath(xpathExpressionToValidate.trim());
-			// ...success
-			return XPATH_VALID;
-		} catch (InvalidXPathException e) {
-			// ...failed to parse the XPath expression: notify of the error
-			return XPATH_INVALID;
-		}
-	}
-
-	/**
-	 * Tests validity of the configuration held in this bean.
-	 *
-	 * @return <code>true</code> if the configuration in the bean is valid;
-	 *         <code>false</code> otherwise.
-	 */
-	public boolean isValid() {
-		return (xpathExpression != null
-				&& validateXPath(xpathExpression) == XPATH_VALID && getXpathNamespaceMap() != null);
-	}
-
-	public String getXmlDocument() {
-		return xmlDocument;
-	}
-
-	@ConfigurationProperty(name = "exampleXmlDocument", label = "Example XML document", required = false)
-	public void setXmlDocument(String xmlDocument) {
-		this.xmlDocument = xmlDocument;
-	}
-
-	public String getXpathExpression() {
-		return xpathExpression;
-	}
-
-	@ConfigurationProperty(name = "xpathExpression", label = "XPath expression")
-	public void setXpathExpression(String xpathExpression) {
-		this.xpathExpression = xpathExpression;
-	}
-
-	public Map<String, String> getXpathNamespaceMap() {
-		return xpathNamespaceMap;
-	}
-
-	public void setXpathNamespaceMap(Map<String, String> xpathNamespaceMap) {
-		this.xpathNamespaceMap = xpathNamespaceMap;
-	}
-
-	@ConfigurationProperty(name = "xpathNamespaceMap", label = "XPath Namespace Map", required = false)
-	public void setXpathNamespaceMap(Set<NamespaceMapping> xpathNamespaceMap) {
-		Map<String, String> namespaceMap = new HashMap<String, String>();
-		for (NamespaceMapping namespaceMapping : xpathNamespaceMap) {
-			namespaceMap.put(namespaceMapping.getPrefix(), namespaceMapping.getUri().toASCIIString());
-		}
-		setXpathNamespaceMap(namespaceMap);
-	}
-
-	@ConfigurationBean(uri = URI + "/NamespaceMapping")
-	public static class NamespaceMapping {
-		private String prefix;
-
-		private URI uri;
-
-		public String getPrefix() {
-			return prefix;
-		}
-
-		@ConfigurationProperty(name = "prefix", label = "Namespace Prefix")
-		public void setPrefix(String prefix) {
-			this.prefix = prefix;
-		}
-
-		public URI getUri() {
-			return uri;
-		}
-
-		@ConfigurationProperty(name = "uri", label = "Namespace URI")
-		public void setUri(URI uri) {
-			this.uri = uri;
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
deleted file mode 100644
index c5c8e18..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*******************************************************************************
- * 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.xpath;
-
-import static net.sf.taverna.t2.activities.xpath.XPathActivity.IN_XML;
-import static net.sf.taverna.t2.activities.xpath.XPathActivity.OUT_TEXT;
-import static net.sf.taverna.t2.activities.xpath.XPathActivity.OUT_XML;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.HashSet;
-import java.util.Set;
-
-import net.sf.taverna.t2.workflowmodel.Edits;
-import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityConfigurationException;
-import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityFactory;
-import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
-import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityOutputPort;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-/**
- * An {@link ActivityFactory} for creating <code>XPathActivity</code>.
- *
- * @author David Withers
- */
-public class XPathActivityFactory implements ActivityFactory {
-
-	private Edits edits;
-
-	@Override
-	public XPathActivity createActivity() {
-		return new XPathActivity();
-	}
-
-	@Override
-	public URI getActivityType() {
-		return URI.create(XPathActivity.URI);
-	}
-
-	@Override
-	public JsonNode getActivityConfigurationSchema() {
-		ObjectMapper objectMapper = new ObjectMapper();
-		try {
-			return objectMapper.readTree(getClass().getResource("/schema.json"));
-		} catch (IOException e) {
-			return objectMapper.createObjectNode();
-		}
-	}
-
-	@Override
-	public Set<ActivityInputPort> getInputPorts(JsonNode configuration)
-			throws ActivityConfigurationException {
-		Set<ActivityInputPort> outputPorts = new HashSet<>();
-		outputPorts.add(edits.createActivityInputPort(IN_XML, 0, true, null,
-				String.class));
-		return outputPorts;
-	}
-
-	@Override
-	public Set<ActivityOutputPort> getOutputPorts(JsonNode configuration)
-			throws ActivityConfigurationException {
-		Set<ActivityOutputPort> outputPorts = new HashSet<>();
-		outputPorts.add(edits.createActivityOutputPort(OUT_TEXT, 1, 1));
-		outputPorts.add(edits.createActivityOutputPort(OUT_XML, 1, 1));
-		return outputPorts;
-	}
-
-	public void setEdits(Edits edits) {
-		this.edits = edits;
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
deleted file mode 100644
index adf10d2..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.sf.taverna.t2.activities.xpath;
-
-import net.sf.taverna.t2.visit.VisitKind;
-import net.sf.taverna.t2.visit.Visitor;
-
-/**
- * A <code>XPathActivityHealthCheck</code> is a kind of visit that determines if
- * the corresponding XPath activity in a workflow (normally an Activity) will
- * work during a workflow run.
- * 
- * @author Sergejs Aleksejevs
- */
-public class XPathActivityHealthCheck extends VisitKind {
-
-	// The following values indicate the type of results that can be associated
-	// with a VisitReport generated by a health-checking visitor.
-
-	public static final int CORRECTLY_CONFIGURED = 0;
-	public static final int EMPTY_XPATH_EXPRESSION = 5;
-	public static final int INVALID_XPATH_EXPRESSION = 10;
-	public static final int GENERAL_CONFIG_PROBLEM = 15;
-
-	public static final int NO_EXAMPLE_DOCUMENT = 20;
-	public static final int MISSING_NAMESPACE_MAPPINGS = 25;
-
-	@Override
-	public Class<? extends Visitor<?>> getVisitorClass() {
-		return XPathActivityHealthChecker.class;
-	}
-
-	private static class Singleton {
-		private static XPathActivityHealthCheck instance = new XPathActivityHealthCheck();
-	}
-
-	public static XPathActivityHealthCheck getInstance() {
-		return Singleton.instance;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
deleted file mode 100644
index 7058841..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
+++ /dev/null
@@ -1,139 +0,0 @@
-package net.sf.taverna.t2.activities.xpath;
-
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.CORRECTLY_CONFIGURED;
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.EMPTY_XPATH_EXPRESSION;
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.GENERAL_CONFIG_PROBLEM;
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.INVALID_XPATH_EXPRESSION;
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.MISSING_NAMESPACE_MAPPINGS;
-import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.NO_EXAMPLE_DOCUMENT;
-import static net.sf.taverna.t2.activities.xpath.XPathUtils.XPATH_EMPTY;
-import static net.sf.taverna.t2.activities.xpath.XPathUtils.XPATH_INVALID;
-import static net.sf.taverna.t2.activities.xpath.XPathUtils.isValid;
-import static net.sf.taverna.t2.activities.xpath.XPathUtils.validateXPath;
-import static net.sf.taverna.t2.visit.VisitReport.getWorstStatus;
-import static net.sf.taverna.t2.visit.VisitReport.Status.OK;
-import static net.sf.taverna.t2.visit.VisitReport.Status.SEVERE;
-import static net.sf.taverna.t2.visit.VisitReport.Status.WARNING;
-import static net.sf.taverna.t2.workflowmodel.health.HealthCheck.NO_PROBLEM;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.sf.taverna.t2.visit.VisitKind;
-import net.sf.taverna.t2.visit.VisitReport;
-import net.sf.taverna.t2.visit.VisitReport.Status;
-import net.sf.taverna.t2.workflowmodel.health.HealthChecker;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-/**
- * A {@link HealthChecker} for a {@link XPathActivity}.
- * 
- * @author Sergejs Aleksejevs
- */
-public class XPathActivityHealthChecker implements HealthChecker<XPathActivity> {
-	@Override
-	public boolean canVisit(Object subject) {
-		return (subject instanceof XPathActivity);
-	}
-
-	@Override
-	public VisitReport visit(XPathActivity activity, List<Object> ancestors) {
-		VisitKind kind = XPathActivityHealthCheck.getInstance();
-		/* collection of validation reports that this health checker will create */
-		List<VisitReport> reports = new ArrayList<VisitReport>();
-
-		JsonNode configBean = activity.getConfiguration();
-		if (isValid(configBean)) {
-			reports.add(new VisitReport(kind, activity,
-					"XPath Activity is configured correctly",
-					CORRECTLY_CONFIGURED, OK));
-		} else {
-			int xpathStatus = validateXPath(configBean.get("xpathExpression")
-					.textValue());
-			if (xpathStatus == XPATH_EMPTY) {
-				reports.add(new VisitReport(kind, activity,
-						"XPath Activity - XPath expression is missing",
-						EMPTY_XPATH_EXPRESSION, SEVERE));
-			} else if (xpathStatus == XPATH_INVALID) {
-				reports.add(new VisitReport(kind, activity,
-						"XPath Activity - XPath expression is invalid",
-						INVALID_XPATH_EXPRESSION, SEVERE));
-			} else {
-				reports.add(new VisitReport(kind, activity,
-						"XPath Activity - bad configuration",
-						GENERAL_CONFIG_PROBLEM, SEVERE));
-			}
-		}
-
-		// warn if there is no example XML document
-		if (!configBean.has("exampleXmlDocument")
-				|| configBean.get("exampleXmlDocument").textValue().trim()
-						.length() == 0) {
-			reports.add(new VisitReport(kind, activity,
-					"XPath activity - no example XML document",
-					NO_EXAMPLE_DOCUMENT, WARNING));
-		}
-
-		// warn if there are no namespace mappings
-		if (hasMissingNamespaceMappings(configBean)) {
-			reports.add(new VisitReport(kind, activity,
-					"XPath activity - has missing namespace mappings",
-					MISSING_NAMESPACE_MAPPINGS, SEVERE));
-		}
-
-		// collect all reports together
-		Status worstStatus = getWorstStatus(reports);
-		VisitReport report = new VisitReport(kind, activity,
-				"XPath Activity Report", NO_PROBLEM, worstStatus, reports);
-
-		return report;
-	}
-
-	/**
-	 * Health check for the XPath activity only involves verifying details in
-	 * the configuration bean - that is quick.
-	 */
-	@Override
-	public boolean isTimeConsuming() {
-		return false;
-	}
-
-	private boolean hasMissingNamespaceMappings(JsonNode json) {
-		List<String> missingNamespaces = new ArrayList<String>();
-
-		for (String xpathLeg : json.get("xpathExpression").textValue()
-				.split("/")) {
-			String[] legFragments = xpathLeg.split(":");
-			if (legFragments.length == 2) {
-				/*
-				 * two fragments - the first is the prefix; check if it's in the
-				 * mappings table
-				 */
-				String fragment = legFragments[0];
-				if (fragment.startsWith("@")) {
-					if (fragment.length() == 1)
-						continue;
-					fragment = fragment.substring(1);
-				}
-				Map<String, String> xpathNamespaceMap = null;
-				if (json.has("xpathNamespaceMap")) {
-					xpathNamespaceMap = new HashMap<>();
-					for (JsonNode namespaceMapping : json
-							.get("xpathNamespaceMap"))
-						xpathNamespaceMap.put(namespaceMapping.get("prefix")
-								.textValue(), namespaceMapping.get("uri")
-								.textValue());
-				}
-				if (xpathNamespaceMap == null || xpathNamespaceMap.isEmpty()
-						|| !xpathNamespaceMap.containsKey(fragment))
-					missingNamespaces.add(fragment);
-			}
-		}
-
-		return ! missingNamespaces.isEmpty();
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java b/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
deleted file mode 100644
index c5f0787..0000000
--- a/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2013 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.xpath;
-
-import static org.dom4j.DocumentHelper.createXPath;
-
-import org.dom4j.DocumentHelper;
-import org.dom4j.InvalidXPathException;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-/**
- * Utility methods for validating xpath expressions.
- * 
- * @author David Withers
- */
-public class XPathUtils {
-
-	public static final int XPATH_VALID = 1;
-	public static final int XPATH_EMPTY = 0;
-	public static final int XPATH_INVALID = -1;
-
-	/**
-	 * Validates an XPath expression.
-	 * 
-	 * @return {@link XPathActivityConfigurationBean#XPATH_VALID XPATH_VALID} -
-	 *         if the expression is valid;<br/>
-	 *         {@link XPathActivityConfigurationBean#XPATH_EMPTY XPATH_EMPTY} -
-	 *         if expression is empty;<br/>
-	 *         {@link XPathActivityConfigurationBean#XPATH_INVALID
-	 *         XPATH_INVALID} - if the expression is invalid / ill-formed.<br/>
-	 */
-	public static int validateXPath(String xpathExpressionToValidate) {
-		// no XPath expression
-		if (xpathExpressionToValidate == null
-				|| xpathExpressionToValidate.trim().isEmpty()) {
-			return XPATH_EMPTY;
-		}
-
-		try {
-			// try to parse the XPath expression...
-			createXPath(xpathExpressionToValidate.trim());
-			// ...success
-			return XPATH_VALID;
-		} catch (InvalidXPathException e) {
-			// ...failed to parse the XPath expression: notify of the error
-			return XPATH_INVALID;
-		}
-	}
-
-	/**
-	 * Tests validity of the configuration held.
-	 * 
-	 * @return <code>true</code> if the configuration in the bean is valid;
-	 *         <code>false</code> otherwise.
-	 */
-	public static boolean isValid(JsonNode json) {
-		return (json.has("xpathExpression")
-				&& validateXPath(json.get("xpathExpression").textValue()) == XPATH_VALID && json
-					.has("xpathNamespaceMap"));
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer b/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
deleted file mode 100644
index cb85b26..0000000
--- a/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
+++ /dev/null
@@ -1 +0,0 @@
-net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheckVisitExplainer
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker b/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
deleted file mode 100644
index 0e69024..0000000
--- a/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
+++ /dev/null
@@ -1 +0,0 @@
-net.sf.taverna.t2.activities.xpath.XPathActivityHealthChecker
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml b/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
deleted file mode 100644
index 69d23b2..0000000
--- a/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:beans="http://www.springframework.org/schema/beans"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans
-                      http://www.springframework.org/schema/beans/spring-beans.xsd
-                      http://www.springframework.org/schema/osgi
-                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
-
-	<service ref="XPathActivityHealthChecker" interface="net.sf.taverna.t2.workflowmodel.health.HealthChecker" />
-
-	<service ref="xPathActivityFactory" interface="net.sf.taverna.t2.workflowmodel.processor.activity.ActivityFactory" />
-
-	<reference id="edits" interface="net.sf.taverna.t2.workflowmodel.Edits" />
-
-</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/resources/META-INF/spring/xpath-activity-context.xml
----------------------------------------------------------------------
diff --git a/src/main/resources/META-INF/spring/xpath-activity-context.xml b/src/main/resources/META-INF/spring/xpath-activity-context.xml
deleted file mode 100644
index 983d4e5..0000000
--- a/src/main/resources/META-INF/spring/xpath-activity-context.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans
-                      http://www.springframework.org/schema/beans/spring-beans.xsd">
-
-	<bean id="XPathActivityHealthChecker" class="net.sf.taverna.t2.activities.xpath.XPathActivityHealthChecker" />
-
-	<bean id="xPathActivityFactory" class="net.sf.taverna.t2.activities.xpath.XPathActivityFactory">
-		<property name="edits" ref="edits" />
-	</bean>
-
-</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/src/main/resources/schema.json
----------------------------------------------------------------------
diff --git a/src/main/resources/schema.json b/src/main/resources/schema.json
deleted file mode 100644
index 81f9f78..0000000
--- a/src/main/resources/schema.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-    "$schema": "http://json-schema.org/draft-03/schema#",
-    "id": "http://ns.taverna.org.uk/2010/activity/xpath.schema.json",
-    "title": "XPath activity configuration",
-    "type": "object",
-    "properties": {
-        "@context": {
-            "description": "JSON-LD context for interpreting the configuration as RDF",
-            "required": true,
-            "enum": ["http://ns.taverna.org.uk/2010/activity/xpath.context.json"]
-        },
-        "exampleXmlDocument": {
-            "title": "Example XML document",
-            "type": "string",
-            "required": false,
-        },
-        "xpathExpression": {
-            "title": "XPath expression",
-            "type": "string",
-            "required": true,
-        },
-        "xpathNamespaceMap": {
-            "title": "XPath Namespace Map",
-            "type": "array",
-            "required": false,
-            "items": { "type": "object", "$ref": "#/definitions/namespaceMapping" }
-        }
-    },
-    "definitions": {
-    	"namespaceMapping": {
-            "properties": {
-           		"prefix": {
-            		"title": "Namespace Prefix",
-            		"type": "string",
-		          	"required": true
-           		},
-           		"uri": {
-            		"title": "Namespace URI,
-            		"type": "string",
- 		         	"required": true
-            	}
-            }
-    	}
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/pom.xml b/taverna-xpath-activity/pom.xml
new file mode 100644
index 0000000..ecf89fa
--- /dev/null
+++ b/taverna-xpath-activity/pom.xml
@@ -0,0 +1,78 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>net.sf.taverna</groupId>
+		<artifactId>taverna-parent</artifactId>
+		<version>3.0.1-SNAPSHOT</version>
+	</parent>
+	<groupId>net.sf.taverna.t2.activities</groupId>
+	<artifactId>xpath-activity</artifactId>
+	<version>2.0.1-SNAPSHOT</version>
+	<name>Taverna XPath Activity</name>
+	<packaging>bundle</packaging>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Import-Package>org.jaxen,*</Import-Package>
+					</instructions>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	<repositories>
+		<repository>
+			<releases />
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<id>mygrid-repository</id>
+			<name>myGrid Repository</name>
+			<url>http://www.mygrid.org.uk/maven/repository</url>
+		</repository>
+		<repository>
+			<releases>
+				<enabled>false</enabled>
+			</releases>
+			<snapshots />
+			<id>mygrid-snapshot-repository</id>
+			<name>myGrid Snapshot Repository</name>
+			<url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
+		</repository>
+	</repositories>
+	<scm>
+		<connection>scm:git:https://github.com/taverna/taverna-xpath-activity.git</connection>
+		<developerConnection>scm:git:ssh://git@github.com/taverna/taverna-xpath-activity.git</developerConnection>
+		<url>https://github.com/taverna/taverna-xpath-activity/</url>
+		<tag>master</tag>
+	</scm>
+
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.core</groupId>
+			<artifactId>reference-api</artifactId>
+			<version>${t2.core.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.core</groupId>
+			<artifactId>workflowmodel-api</artifactId>
+			<version>${t2.core.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.dom4j</groupId>
+			<artifactId>com.springsource.org.dom4j</artifactId>
+			<version>${dom4j.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.jaxen</groupId>
+			<artifactId>com.springsource.org.jaxen</artifactId>
+			<version>${jaxen.version}</version>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
new file mode 100644
index 0000000..260eb5a
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivity.java
@@ -0,0 +1,211 @@
+package net.sf.taverna.t2.activities.xpath;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.taverna.t2.invocation.InvocationContext;
+import net.sf.taverna.t2.reference.ErrorDocumentService;
+import net.sf.taverna.t2.reference.ReferenceService;
+import net.sf.taverna.t2.reference.T2Reference;
+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.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.InvalidXPathException;
+import org.dom4j.Node;
+import org.dom4j.XPath;
+import org.dom4j.XPathException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Enhanced XPath activity.
+ *
+ * @author Sergejs Aleksejevs
+ */
+public class XPathActivity extends AbstractAsynchronousActivity<JsonNode> {
+
+	public static final String URI = "http://ns.taverna.org.uk/2010/activity/xpath";
+
+	// These ports are default ones (and only ones - XPath activity will not have dynamic ports)
+	public static final String IN_XML = "xml_text";
+	public static final String OUT_TEXT = "nodelist";
+	public static final String OUT_XML = "nodelistAsXML";
+
+	private static final String SINGLE_VALUE_TEXT = "firstNode";
+	private static final String SINGLE_VALUE_XML = "firstNodeAsXML";
+	
+	// Configuration bean for this activity - essentially defines a particular instance
+	// of the activity through the values of its parameters
+	private JsonNode json;
+
+	@Override
+	public JsonNode getConfiguration() {
+		return this.json;
+	}
+
+	@Override
+	public void configure(JsonNode json) throws ActivityConfigurationException {
+		// Check configBean is valid
+		if (!XPathUtils.isValid(json)) {
+			throw new ActivityConfigurationException("Invalid configuration of XPath activity...");
+			// TODO - check this
+		}
+
+		// Store for getConfiguration()
+		this.json = json;
+	}
+
+	protected void configurePorts() {
+		// ---- REMOVE OLD PORTS ----
+	  
+		// In case we are being reconfigured - remove existing ports first to avoid duplicates
+		removeInputs();
+		removeOutputs();
+
+		// ---- CREATE NEW INPUTS AND OUTPUTS ----
+		
+		// all ports in this activity are static, so no dependency on the values in config bean
+		
+		// single input port: the input XML text will be treated as String for now
+		addInput(IN_XML, 0, true, null, String.class);
+
+		addOutput(SINGLE_VALUE_TEXT, 0);
+		addOutput(SINGLE_VALUE_XML, 0);
+		addOutput(OUT_TEXT, 1);
+		addOutput(OUT_XML, 1);
+	}
+
+	/**
+	 * This method executes pre-configured instance of XPath activity.
+	 */
+	@Override
+	public void executeAsynch(final Map<String, T2Reference> inputs,
+			final AsynchronousActivityCallback callback) {
+		// Don't execute service directly now, request to be run asynchronously
+		callback.requestRun(new Runnable() {
+			@Override
+			@SuppressWarnings("unchecked")
+			public void run() {
+
+				InvocationContext context = callback.getContext();
+				ReferenceService referenceService = context.getReferenceService();
+
+				// ---- RESOLVE INPUT ----
+
+				String xmlInput = (String) referenceService.renderIdentifier(inputs.get(IN_XML),
+						String.class, context);
+
+				// ---- DO THE ACTUAL SERVICE INVOCATION ----
+
+				List<Node> matchingNodes = new ArrayList<Node>();
+
+				// only attempt to execute XPath expression if there is some input data
+				if (xmlInput != null && xmlInput.length() > 0) {
+					// XPath configuration is taken from the config bean
+					try {
+						XPath expr = DocumentHelper.createXPath(json.get("xpathExpression").textValue());
+						Map<String, String> xpathNamespaceMap = new HashMap<>();
+						for (JsonNode namespaceMapping : json.get("xpathNamespaceMap")) {
+							xpathNamespaceMap.put(namespaceMapping.get("prefix").textValue(),
+									namespaceMapping.get("uri").textValue());
+						}
+						expr.setNamespaceURIs(xpathNamespaceMap);
+						Document doc = DocumentHelper.parseText(xmlInput);
+						matchingNodes = expr.selectNodes(doc);
+					} catch (InvalidXPathException e) {
+						callback.fail("Incorrect XPath Expression -- XPath processing library "
+								+ "reported the following error: " + e.getMessage(), e);
+
+						// make sure we don't call callback.receiveResult later
+						return;
+					} catch (DocumentException e) {
+						callback.fail("XML document was not valid -- XPath processing library "
+								+ "reported the following error: " + e.getMessage(), e);
+
+						// make sure we don't call callback.receiveResult later
+						return;
+					} catch (XPathException e) {
+						callback.fail(
+								"Unexpected error has occurred while executing the XPath expression. "
+										+ "-- XPath processing library reported the following error:\n"
+										+ e.getMessage(), e);
+
+						// make sure we don't call callback.receiveResult later
+						return;
+					}
+				}
+				
+				// --- PREPARE OUTPUTS ---
+
+				List<String> outNodesText = new ArrayList<String>();
+				List<String> outNodesXML = new ArrayList<String>();
+				Object textValue = null;
+				Object xmlValue = null;
+
+				for (Object o : matchingNodes) {
+					if (o instanceof Node) {
+						Node n = (Node) o;
+						if (n.getStringValue() != null
+								&& n.getStringValue().length() > 0) {
+							outNodesText.add(n.getStringValue());
+							if (textValue == null)
+								textValue = n.getStringValue();
+						}
+						outNodesXML.add(n.asXML());
+						if (xmlValue == null)
+							xmlValue = n.asXML();
+					} else {
+						outNodesText.add(o.toString());
+						if (textValue == null)
+							textValue = o.toString();
+					}
+				}
+
+				// ---- REGISTER OUTPUTS ----
+
+				Map<String, T2Reference> outputs = new HashMap<String, T2Reference>();
+				if (textValue == null) {
+					ErrorDocumentService errorDocService = referenceService
+							.getErrorDocumentService();
+					textValue = errorDocService.registerError(
+							"No value produced", 0, callback.getContext());
+				}
+
+				if (xmlValue == null) {
+					ErrorDocumentService errorDocService = referenceService
+							.getErrorDocumentService();
+					xmlValue = errorDocService.registerError(
+							"No value produced", 0, callback.getContext());
+				}
+
+				T2Reference firstNodeAsText = referenceService.register(
+						textValue, 0, true, context);
+				outputs.put(SINGLE_VALUE_TEXT, firstNodeAsText);
+
+				T2Reference firstNodeAsXml = referenceService.register(
+						xmlValue, 0, true, context);
+				outputs.put(SINGLE_VALUE_XML, firstNodeAsXml);
+
+				T2Reference outNodesAsText = referenceService.register(
+						outNodesText, 1, true, context);
+				outputs.put(OUT_TEXT, outNodesAsText);
+
+				T2Reference outNodesAsXML = referenceService.register(
+						outNodesXML, 1, true, context);
+				outputs.put(OUT_XML, outNodesAsXML);
+
+				// return map of output data, with empty index array as this is
+				// the only and final result (this index parameter is used if
+				// pipelining output)
+				callback.receiveResult(outputs, new int[0]);
+			}
+		});
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
new file mode 100644
index 0000000..12bd536
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityConfigurationBean.java
@@ -0,0 +1,145 @@
+package net.sf.taverna.t2.activities.xpath;
+
+import static net.sf.taverna.t2.activities.xpath.XPathActivity.URI;
+import static org.dom4j.DocumentHelper.createXPath;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationBean;
+import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationProperty;
+
+import org.dom4j.DocumentException;
+import org.dom4j.InvalidXPathException;
+
+/**
+ *
+ * @author Sergejs Aleksejevs
+ */
+@ConfigurationBean(uri = URI + "#Config")
+public class XPathActivityConfigurationBean implements Serializable {
+	// --- CONSTANTS ---
+	public static final int XPATH_VALID = XPathUtils.XPATH_VALID;
+	public static final int XPATH_EMPTY = XPathUtils.XPATH_EMPTY;
+	public static final int XPATH_INVALID = XPathUtils.XPATH_INVALID;
+
+	private String xmlDocument;
+	private String xpathExpression;
+	private Map<String, String> xpathNamespaceMap;
+
+	/**
+	 * @return An instance of the {@link XPathActivityConfigurationBean}
+	 *         pre-configured with default settings for all parameters.
+	 * @throws DocumentException
+	 */
+	public static XPathActivityConfigurationBean getDefaultInstance() {
+		// document will not be set
+		XPathActivityConfigurationBean defaultBean = new XPathActivityConfigurationBean();
+		defaultBean.setXpathExpression("/");
+		defaultBean.setXpathNamespaceMap(new HashMap<String, String>(0));
+
+		return (defaultBean);
+	}
+
+	/**
+	 * Validates an XPath expression.
+	 *
+	 * @return {@link XPathActivityConfigurationBean#XPATH_VALID XPATH_VALID} -
+	 *         if the expression is valid;<br/>
+	 *         {@link XPathActivityConfigurationBean#XPATH_EMPTY XPATH_EMPTY} -
+	 *         if expression is empty;<br/>
+	 *         {@link XPathActivityConfigurationBean#XPATH_INVALID
+	 *         XPATH_INVALID} - if the expression is invalid / ill-formed.<br/>
+	 */
+	public static int validateXPath(String xpathExpressionToValidate) {
+		// no XPath expression
+		if (xpathExpressionToValidate == null
+				|| xpathExpressionToValidate.trim().isEmpty()) {
+			return XPATH_EMPTY;
+		}
+
+		try {
+			// try to parse the XPath expression...
+			createXPath(xpathExpressionToValidate.trim());
+			// ...success
+			return XPATH_VALID;
+		} catch (InvalidXPathException e) {
+			// ...failed to parse the XPath expression: notify of the error
+			return XPATH_INVALID;
+		}
+	}
+
+	/**
+	 * Tests validity of the configuration held in this bean.
+	 *
+	 * @return <code>true</code> if the configuration in the bean is valid;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean isValid() {
+		return (xpathExpression != null
+				&& validateXPath(xpathExpression) == XPATH_VALID && getXpathNamespaceMap() != null);
+	}
+
+	public String getXmlDocument() {
+		return xmlDocument;
+	}
+
+	@ConfigurationProperty(name = "exampleXmlDocument", label = "Example XML document", required = false)
+	public void setXmlDocument(String xmlDocument) {
+		this.xmlDocument = xmlDocument;
+	}
+
+	public String getXpathExpression() {
+		return xpathExpression;
+	}
+
+	@ConfigurationProperty(name = "xpathExpression", label = "XPath expression")
+	public void setXpathExpression(String xpathExpression) {
+		this.xpathExpression = xpathExpression;
+	}
+
+	public Map<String, String> getXpathNamespaceMap() {
+		return xpathNamespaceMap;
+	}
+
+	public void setXpathNamespaceMap(Map<String, String> xpathNamespaceMap) {
+		this.xpathNamespaceMap = xpathNamespaceMap;
+	}
+
+	@ConfigurationProperty(name = "xpathNamespaceMap", label = "XPath Namespace Map", required = false)
+	public void setXpathNamespaceMap(Set<NamespaceMapping> xpathNamespaceMap) {
+		Map<String, String> namespaceMap = new HashMap<String, String>();
+		for (NamespaceMapping namespaceMapping : xpathNamespaceMap) {
+			namespaceMap.put(namespaceMapping.getPrefix(), namespaceMapping.getUri().toASCIIString());
+		}
+		setXpathNamespaceMap(namespaceMap);
+	}
+
+	@ConfigurationBean(uri = URI + "/NamespaceMapping")
+	public static class NamespaceMapping {
+		private String prefix;
+
+		private URI uri;
+
+		public String getPrefix() {
+			return prefix;
+		}
+
+		@ConfigurationProperty(name = "prefix", label = "Namespace Prefix")
+		public void setPrefix(String prefix) {
+			this.prefix = prefix;
+		}
+
+		public URI getUri() {
+			return uri;
+		}
+
+		@ConfigurationProperty(name = "uri", label = "Namespace URI")
+		public void setUri(URI uri) {
+			this.uri = uri;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
new file mode 100644
index 0000000..c5c8e18
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityFactory.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * 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.xpath;
+
+import static net.sf.taverna.t2.activities.xpath.XPathActivity.IN_XML;
+import static net.sf.taverna.t2.activities.xpath.XPathActivity.OUT_TEXT;
+import static net.sf.taverna.t2.activities.xpath.XPathActivity.OUT_XML;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.HashSet;
+import java.util.Set;
+
+import net.sf.taverna.t2.workflowmodel.Edits;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityConfigurationException;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityFactory;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityInputPort;
+import net.sf.taverna.t2.workflowmodel.processor.activity.ActivityOutputPort;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * An {@link ActivityFactory} for creating <code>XPathActivity</code>.
+ *
+ * @author David Withers
+ */
+public class XPathActivityFactory implements ActivityFactory {
+
+	private Edits edits;
+
+	@Override
+	public XPathActivity createActivity() {
+		return new XPathActivity();
+	}
+
+	@Override
+	public URI getActivityType() {
+		return URI.create(XPathActivity.URI);
+	}
+
+	@Override
+	public JsonNode getActivityConfigurationSchema() {
+		ObjectMapper objectMapper = new ObjectMapper();
+		try {
+			return objectMapper.readTree(getClass().getResource("/schema.json"));
+		} catch (IOException e) {
+			return objectMapper.createObjectNode();
+		}
+	}
+
+	@Override
+	public Set<ActivityInputPort> getInputPorts(JsonNode configuration)
+			throws ActivityConfigurationException {
+		Set<ActivityInputPort> outputPorts = new HashSet<>();
+		outputPorts.add(edits.createActivityInputPort(IN_XML, 0, true, null,
+				String.class));
+		return outputPorts;
+	}
+
+	@Override
+	public Set<ActivityOutputPort> getOutputPorts(JsonNode configuration)
+			throws ActivityConfigurationException {
+		Set<ActivityOutputPort> outputPorts = new HashSet<>();
+		outputPorts.add(edits.createActivityOutputPort(OUT_TEXT, 1, 1));
+		outputPorts.add(edits.createActivityOutputPort(OUT_XML, 1, 1));
+		return outputPorts;
+	}
+
+	public void setEdits(Edits edits) {
+		this.edits = edits;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
new file mode 100644
index 0000000..adf10d2
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthCheck.java
@@ -0,0 +1,38 @@
+package net.sf.taverna.t2.activities.xpath;
+
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.Visitor;
+
+/**
+ * A <code>XPathActivityHealthCheck</code> is a kind of visit that determines if
+ * the corresponding XPath activity in a workflow (normally an Activity) will
+ * work during a workflow run.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class XPathActivityHealthCheck extends VisitKind {
+
+	// The following values indicate the type of results that can be associated
+	// with a VisitReport generated by a health-checking visitor.
+
+	public static final int CORRECTLY_CONFIGURED = 0;
+	public static final int EMPTY_XPATH_EXPRESSION = 5;
+	public static final int INVALID_XPATH_EXPRESSION = 10;
+	public static final int GENERAL_CONFIG_PROBLEM = 15;
+
+	public static final int NO_EXAMPLE_DOCUMENT = 20;
+	public static final int MISSING_NAMESPACE_MAPPINGS = 25;
+
+	@Override
+	public Class<? extends Visitor<?>> getVisitorClass() {
+		return XPathActivityHealthChecker.class;
+	}
+
+	private static class Singleton {
+		private static XPathActivityHealthCheck instance = new XPathActivityHealthCheck();
+	}
+
+	public static XPathActivityHealthCheck getInstance() {
+		return Singleton.instance;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
new file mode 100644
index 0000000..7058841
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathActivityHealthChecker.java
@@ -0,0 +1,139 @@
+package net.sf.taverna.t2.activities.xpath;
+
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.CORRECTLY_CONFIGURED;
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.EMPTY_XPATH_EXPRESSION;
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.GENERAL_CONFIG_PROBLEM;
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.INVALID_XPATH_EXPRESSION;
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.MISSING_NAMESPACE_MAPPINGS;
+import static net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheck.NO_EXAMPLE_DOCUMENT;
+import static net.sf.taverna.t2.activities.xpath.XPathUtils.XPATH_EMPTY;
+import static net.sf.taverna.t2.activities.xpath.XPathUtils.XPATH_INVALID;
+import static net.sf.taverna.t2.activities.xpath.XPathUtils.isValid;
+import static net.sf.taverna.t2.activities.xpath.XPathUtils.validateXPath;
+import static net.sf.taverna.t2.visit.VisitReport.getWorstStatus;
+import static net.sf.taverna.t2.visit.VisitReport.Status.OK;
+import static net.sf.taverna.t2.visit.VisitReport.Status.SEVERE;
+import static net.sf.taverna.t2.visit.VisitReport.Status.WARNING;
+import static net.sf.taverna.t2.workflowmodel.health.HealthCheck.NO_PROBLEM;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.visit.VisitReport.Status;
+import net.sf.taverna.t2.workflowmodel.health.HealthChecker;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * A {@link HealthChecker} for a {@link XPathActivity}.
+ * 
+ * @author Sergejs Aleksejevs
+ */
+public class XPathActivityHealthChecker implements HealthChecker<XPathActivity> {
+	@Override
+	public boolean canVisit(Object subject) {
+		return (subject instanceof XPathActivity);
+	}
+
+	@Override
+	public VisitReport visit(XPathActivity activity, List<Object> ancestors) {
+		VisitKind kind = XPathActivityHealthCheck.getInstance();
+		/* collection of validation reports that this health checker will create */
+		List<VisitReport> reports = new ArrayList<VisitReport>();
+
+		JsonNode configBean = activity.getConfiguration();
+		if (isValid(configBean)) {
+			reports.add(new VisitReport(kind, activity,
+					"XPath Activity is configured correctly",
+					CORRECTLY_CONFIGURED, OK));
+		} else {
+			int xpathStatus = validateXPath(configBean.get("xpathExpression")
+					.textValue());
+			if (xpathStatus == XPATH_EMPTY) {
+				reports.add(new VisitReport(kind, activity,
+						"XPath Activity - XPath expression is missing",
+						EMPTY_XPATH_EXPRESSION, SEVERE));
+			} else if (xpathStatus == XPATH_INVALID) {
+				reports.add(new VisitReport(kind, activity,
+						"XPath Activity - XPath expression is invalid",
+						INVALID_XPATH_EXPRESSION, SEVERE));
+			} else {
+				reports.add(new VisitReport(kind, activity,
+						"XPath Activity - bad configuration",
+						GENERAL_CONFIG_PROBLEM, SEVERE));
+			}
+		}
+
+		// warn if there is no example XML document
+		if (!configBean.has("exampleXmlDocument")
+				|| configBean.get("exampleXmlDocument").textValue().trim()
+						.length() == 0) {
+			reports.add(new VisitReport(kind, activity,
+					"XPath activity - no example XML document",
+					NO_EXAMPLE_DOCUMENT, WARNING));
+		}
+
+		// warn if there are no namespace mappings
+		if (hasMissingNamespaceMappings(configBean)) {
+			reports.add(new VisitReport(kind, activity,
+					"XPath activity - has missing namespace mappings",
+					MISSING_NAMESPACE_MAPPINGS, SEVERE));
+		}
+
+		// collect all reports together
+		Status worstStatus = getWorstStatus(reports);
+		VisitReport report = new VisitReport(kind, activity,
+				"XPath Activity Report", NO_PROBLEM, worstStatus, reports);
+
+		return report;
+	}
+
+	/**
+	 * Health check for the XPath activity only involves verifying details in
+	 * the configuration bean - that is quick.
+	 */
+	@Override
+	public boolean isTimeConsuming() {
+		return false;
+	}
+
+	private boolean hasMissingNamespaceMappings(JsonNode json) {
+		List<String> missingNamespaces = new ArrayList<String>();
+
+		for (String xpathLeg : json.get("xpathExpression").textValue()
+				.split("/")) {
+			String[] legFragments = xpathLeg.split(":");
+			if (legFragments.length == 2) {
+				/*
+				 * two fragments - the first is the prefix; check if it's in the
+				 * mappings table
+				 */
+				String fragment = legFragments[0];
+				if (fragment.startsWith("@")) {
+					if (fragment.length() == 1)
+						continue;
+					fragment = fragment.substring(1);
+				}
+				Map<String, String> xpathNamespaceMap = null;
+				if (json.has("xpathNamespaceMap")) {
+					xpathNamespaceMap = new HashMap<>();
+					for (JsonNode namespaceMapping : json
+							.get("xpathNamespaceMap"))
+						xpathNamespaceMap.put(namespaceMapping.get("prefix")
+								.textValue(), namespaceMapping.get("uri")
+								.textValue());
+				}
+				if (xpathNamespaceMap == null || xpathNamespaceMap.isEmpty()
+						|| !xpathNamespaceMap.containsKey(fragment))
+					missingNamespaces.add(fragment);
+			}
+		}
+
+		return ! missingNamespaces.isEmpty();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
new file mode 100644
index 0000000..c5f0787
--- /dev/null
+++ b/taverna-xpath-activity/src/main/java/net/sf/taverna/t2/activities/xpath/XPathUtils.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (C) 2013 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.xpath;
+
+import static org.dom4j.DocumentHelper.createXPath;
+
+import org.dom4j.DocumentHelper;
+import org.dom4j.InvalidXPathException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Utility methods for validating xpath expressions.
+ * 
+ * @author David Withers
+ */
+public class XPathUtils {
+
+	public static final int XPATH_VALID = 1;
+	public static final int XPATH_EMPTY = 0;
+	public static final int XPATH_INVALID = -1;
+
+	/**
+	 * Validates an XPath expression.
+	 * 
+	 * @return {@link XPathActivityConfigurationBean#XPATH_VALID XPATH_VALID} -
+	 *         if the expression is valid;<br/>
+	 *         {@link XPathActivityConfigurationBean#XPATH_EMPTY XPATH_EMPTY} -
+	 *         if expression is empty;<br/>
+	 *         {@link XPathActivityConfigurationBean#XPATH_INVALID
+	 *         XPATH_INVALID} - if the expression is invalid / ill-formed.<br/>
+	 */
+	public static int validateXPath(String xpathExpressionToValidate) {
+		// no XPath expression
+		if (xpathExpressionToValidate == null
+				|| xpathExpressionToValidate.trim().isEmpty()) {
+			return XPATH_EMPTY;
+		}
+
+		try {
+			// try to parse the XPath expression...
+			createXPath(xpathExpressionToValidate.trim());
+			// ...success
+			return XPATH_VALID;
+		} catch (InvalidXPathException e) {
+			// ...failed to parse the XPath expression: notify of the error
+			return XPATH_INVALID;
+		}
+	}
+
+	/**
+	 * Tests validity of the configuration held.
+	 * 
+	 * @return <code>true</code> if the configuration in the bean is valid;
+	 *         <code>false</code> otherwise.
+	 */
+	public static boolean isValid(JsonNode json) {
+		return (json.has("xpathExpression")
+				&& validateXPath(json.get("xpathExpression").textValue()) == XPATH_VALID && json
+					.has("xpathNamespaceMap"));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer b/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
new file mode 100644
index 0000000..cb85b26
--- /dev/null
+++ b/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.report.explainer.VisitExplainer
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.xpath.XPathActivityHealthCheckVisitExplainer
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker b/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
new file mode 100644
index 0000000..0e69024
--- /dev/null
+++ b/taverna-xpath-activity/src/main/resources/META-INF/services/net.sf.taverna.t2.workflowmodel.health.HealthChecker
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.xpath.XPathActivityHealthChecker
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml b/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
new file mode 100644
index 0000000..69d23b2
--- /dev/null
+++ b/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context-osgi.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+	<service ref="XPathActivityHealthChecker" interface="net.sf.taverna.t2.workflowmodel.health.HealthChecker" />
+
+	<service ref="xPathActivityFactory" interface="net.sf.taverna.t2.workflowmodel.processor.activity.ActivityFactory" />
+
+	<reference id="edits" interface="net.sf.taverna.t2.workflowmodel.Edits" />
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context.xml
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context.xml b/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context.xml
new file mode 100644
index 0000000..983d4e5
--- /dev/null
+++ b/taverna-xpath-activity/src/main/resources/META-INF/spring/xpath-activity-context.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="XPathActivityHealthChecker" class="net.sf.taverna.t2.activities.xpath.XPathActivityHealthChecker" />
+
+	<bean id="xPathActivityFactory" class="net.sf.taverna.t2.activities.xpath.XPathActivityFactory">
+		<property name="edits" ref="edits" />
+	</bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d2da8c61/taverna-xpath-activity/src/main/resources/schema.json
----------------------------------------------------------------------
diff --git a/taverna-xpath-activity/src/main/resources/schema.json b/taverna-xpath-activity/src/main/resources/schema.json
new file mode 100644
index 0000000..81f9f78
--- /dev/null
+++ b/taverna-xpath-activity/src/main/resources/schema.json
@@ -0,0 +1,45 @@
+{
+    "$schema": "http://json-schema.org/draft-03/schema#",
+    "id": "http://ns.taverna.org.uk/2010/activity/xpath.schema.json",
+    "title": "XPath activity configuration",
+    "type": "object",
+    "properties": {
+        "@context": {
+            "description": "JSON-LD context for interpreting the configuration as RDF",
+            "required": true,
+            "enum": ["http://ns.taverna.org.uk/2010/activity/xpath.context.json"]
+        },
+        "exampleXmlDocument": {
+            "title": "Example XML document",
+            "type": "string",
+            "required": false,
+        },
+        "xpathExpression": {
+            "title": "XPath expression",
+            "type": "string",
+            "required": true,
+        },
+        "xpathNamespaceMap": {
+            "title": "XPath Namespace Map",
+            "type": "array",
+            "required": false,
+            "items": { "type": "object", "$ref": "#/definitions/namespaceMapping" }
+        }
+    },
+    "definitions": {
+    	"namespaceMapping": {
+            "properties": {
+           		"prefix": {
+            		"title": "Namespace Prefix",
+            		"type": "string",
+		          	"required": true
+           		},
+           		"uri": {
+            		"title": "Namespace URI,
+            		"type": "string",
+ 		         	"required": true
+            	}
+            }
+    	}
+    }
+}