
org.apache.taverna.activities.xpath.XPathActivity Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.taverna.activities.xpath;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.taverna.invocation.InvocationContext;
import org.apache.taverna.reference.ErrorDocumentService;
import org.apache.taverna.reference.ReferenceService;
import org.apache.taverna.reference.T2Reference;
import org.apache.taverna.workflowmodel.processor.activity.AbstractAsynchronousActivity;
import org.apache.taverna.workflowmodel.processor.activity.ActivityConfigurationException;
import org.apache.taverna.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 {
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 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 matchingNodes = new ArrayList();
// 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 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 outNodesText = new ArrayList();
List outNodesXML = new ArrayList();
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 outputs = new HashMap();
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]);
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy