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
+ }
+ }
+ }
+ }
+}