blob: 031de03ae3b49e7fc70c28d5f4b7e90be03d143b [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 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.wsdl.xmlsplitter;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.taverna.wsdl.parser.ArrayTypeDescriptor;
import net.sf.taverna.wsdl.parser.BaseTypeDescriptor;
import net.sf.taverna.wsdl.parser.ComplexTypeDescriptor;
import net.sf.taverna.wsdl.parser.TypeDescriptor;
import org.apache.axis.encoding.Base64;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
public class XMLInputSplitter {
private TypeDescriptor typeDescriptor;
private String[] outputNames;
private String[] inputNames;
private String[] inputTypes;
public XMLInputSplitter(TypeDescriptor typeDescriptor, String inputNames[],
String inputTypes[], String[] outputNames) {
this.typeDescriptor = typeDescriptor;
this.outputNames = outputNames;
this.inputTypes = inputTypes;
this.inputNames = inputNames;
}
public Map<String, String> execute(Map<String, Object> inputMap)
throws JDOMException, IOException {
Map<String, String> result = new HashMap<String, String>();
Element outputElement = (this.typeDescriptor.getName().length() > 0 ? new Element(
this.typeDescriptor.getName())
: new Element(this.typeDescriptor.getType()));
if (typeDescriptor instanceof ComplexTypeDescriptor) {
executeForComplexType(inputMap, result, outputElement);
} else {
for (String key : inputMap.keySet()) {
Object dataObject = inputMap.get(key);
if (dataObject instanceof List) {
Element dataElement = buildElementFromObject(key, "");
for (Object dataItem : ((List<?>) dataObject)) {
Element itemElement = buildElementFromObject(key,
dataItem);
dataElement.addContent(itemElement);
}
XMLOutputter outputter = new XMLOutputter();
String xmlText = outputter.outputString(dataElement);
result.put(outputNames[0], xmlText);
} else {
Element dataElement = buildElementFromObject(key,
dataObject);
outputElement.addContent(dataElement);
XMLOutputter outputter = new XMLOutputter();
String xmlText = outputter.outputString(outputElement);
result.put(outputNames[0], xmlText);
}
}
}
return result;
}
private void executeForComplexType(Map<String, Object> inputMap,
Map<String, String> result, Element outputElement)
throws JDOMException, IOException {
ComplexTypeDescriptor complexDescriptor = (ComplexTypeDescriptor) typeDescriptor;
for (TypeDescriptor elementType : complexDescriptor.getElements()) {
String key = elementType.getName();
Object dataObject = inputMap.get(key);
if (dataObject==null) {
if (elementType.isOptional()) {
continue;
} if (elementType.isNillable()) {
dataObject = "xsi:nil";
} else {
dataObject="";
}
}
if (dataObject instanceof List) {
Element arrayElement = buildElementFromObject(key, "");
String itemkey = "item";
boolean wrapped = false;
if (elementType instanceof ArrayTypeDescriptor) {
wrapped = ((ArrayTypeDescriptor) elementType).isWrapped();
TypeDescriptor arrayElementType = ((ArrayTypeDescriptor) elementType)
.getElementType();
if (!wrapped) {
itemkey = elementType.getName();
} else {
if (arrayElementType.getName() != null
&& arrayElementType.getName().length() > 0) {
itemkey = arrayElementType.getName();
} else {
itemkey = arrayElementType.getType();
}
}
}
for (Object itemObject : ((List<?>)dataObject)) {
Element dataElement = buildElementFromObject(itemkey,
itemObject);
dataElement.setNamespace(Namespace.getNamespace(elementType
.getNamespaceURI()));
if (!wrapped) {
dataElement.setName(itemkey);
outputElement.addContent(dataElement);
} else {
arrayElement.addContent(dataElement);
}
}
if (wrapped)
outputElement.addContent(arrayElement);
} else {
Element dataElement = buildElementFromObject(key, dataObject);
outputElement.addContent(dataElement);
}
}
for (TypeDescriptor attribute : complexDescriptor.getAttributes()) {
String key = attribute.getName();
Object dataObject = inputMap.get("1" + key);
if (dataObject == null) {
dataObject = inputMap.get(key);
}
if (dataObject != null) {
outputElement.setAttribute(key, dataObject.toString(), Namespace
.getNamespace(attribute.getNamespaceURI()));
}
}
outputElement.setNamespace(Namespace.getNamespace(typeDescriptor
.getNamespaceURI()));
XMLOutputter outputter = new XMLOutputter();
String xmlText = outputter.outputString(outputElement);
result.put(outputNames[0], xmlText);
}
private Element buildElementFromObject(String key, Object dataObject)
throws JDOMException, IOException {
Element dataElement = null;
if (isXMLInput(key)) {
dataElement = createDataElementForXMLInput(dataObject, key);
} else {
dataElement = new Element(key);
setDataElementNamespace(key, dataElement);
Namespace xsiNs = org.jdom.Namespace
.getNamespace("xsi",
"http://www.w3.org/2001/XMLSchema-instance");
if (dataObject.toString().equals("xsi:nil")) {
dataElement.setAttribute("nil", "true", xsiNs); // changes nil value
} else {
if (dataObject instanceof byte[]) {
dataElement
.setAttribute(
"type",
"xsd:base64Binary",
xsiNs);
dataObject = Base64
.encode(((byte[]) dataObject));
}
dataElement.setText(dataObject.toString());
}
}
return dataElement;
}
private Element createDataElementForXMLInput(Object dataObject, String key)
throws JDOMException, IOException {
Element dataElement = null;
String xml = dataObject.toString();
if (xml.length() > 0) {
Document doc = new SAXBuilder().build(new StringReader(xml));
dataElement = doc.getRootElement();
dataElement.detach();
} else {
dataElement = new Element(key);
}
setDataElementNamespace(key, dataElement);
return dataElement;
}
// set the namespace if it can be determined from the element TypeDescriptor
// by the key
private void setDataElementNamespace(String key, Element dataElement) {
if (typeDescriptor instanceof ComplexTypeDescriptor) {
TypeDescriptor elementTypeDescriptor = ((ComplexTypeDescriptor) typeDescriptor)
.elementForName(key);
if (elementTypeDescriptor != null) {
String nsURI = null;
if (elementTypeDescriptor instanceof BaseTypeDescriptor) {
nsURI = elementTypeDescriptor.getNamespaceURI();
// this is some protective code against old workflows that
// had the base element namespace incorrectly
// declared (it was using the type NS, rather than the
// element NS.
if (nsURI.contains("XMLSchema")
&& nsURI.contains("http://www.w3.org")) {
nsURI = typeDescriptor.getNamespaceURI();
}
} else {
nsURI = elementTypeDescriptor.getNamespaceURI();
}
if (nsURI != null && nsURI.length() > 0) {
updateElementNamespace(dataElement, nsURI);
}
}
}
}
/**
* Updates the element namespace, and also iterates all descendant elements.
* If these elements have no default namespace, or is blank then it is also
* set to namespaceURI (JDOM by default will not set the child elements to
* the same namespace as the element modified but will override them with
* blank namespaces).
*
* @param dataElement
* @param namespaceURI
*/
private void updateElementNamespace(Element dataElement, String namespaceURI) {
dataElement.setNamespace(Namespace.getNamespace(namespaceURI));
Iterator<?> iterator = dataElement.getDescendants();
while (iterator.hasNext()) {
Object descendantObject = iterator.next();
if (descendantObject instanceof Element) {
Element childElement = (Element) descendantObject;
if (childElement.getNamespaceURI() == null) {
childElement.setNamespace(Namespace
.getNamespace(namespaceURI));
}
}
}
}
private boolean isXMLInput(String key) {
boolean result = false;
for (int i = 0; i < inputNames.length; i++) {
if (inputNames[i].equals(key)) {
result = inputTypes[i].indexOf("'text/xml'") != -1;
}
}
return result;
}
}