blob: 06f12701087319ac273f35da23ace40998af5201 [file] [log] [blame]
/**
*
* 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.airavata.workflow.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.airavata.common.exception.AiravataException;
import org.apache.airavata.common.utils.IOUtil;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import org.xmlpull.infoset.XmlDocument;
import org.xmlpull.infoset.XmlElement;
import org.xmlpull.infoset.XmlNamespace;
import org.xmlpull.mxp1.MXParserFactory;
import org.xmlpull.mxp1_serializer.MXSerializer;
public class XMLUtil {
/**
* The XML builder for XPP5
*/
public static final org.xmlpull.infoset.XmlInfosetBuilder BUILDER = org.xmlpull.infoset.XmlInfosetBuilder
.newInstance();
/**
* The XML builder for XPP3.
*/
public static final org.xmlpull.v1.builder.XmlInfosetBuilder BUILDER3 = org.xmlpull.v1.builder.XmlInfosetBuilder
.newInstance(new MXParserFactory());
private static final Logger logger = LoggerFactory.getLogger(XMLUtil.class);
private final static String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
private final static String INDENT = " ";
/**
* Parses a specified string and returns the XmlElement (XPP3).
*
* @param string
* @return The XmlElement (XPP3) parsed.
*/
public static org.xmlpull.v1.builder.XmlElement stringToXmlElement3(String string) {
return BUILDER3.parseFragmentFromReader(new StringReader(string));
}
/**
* Parses a specified string and returns the XmlElement (XPP5).
*
* @param string
* @return The XmlElement (XPP5) parsed.
*/
public static org.xmlpull.infoset.XmlElement stringToXmlElement(String string) {
XmlDocument document = BUILDER.parseString(string);
org.xmlpull.infoset.XmlElement element = document.getDocumentElement();
return element;
}
/**
* Converts a specified XmlElement (XPP3) to the XmlElement (XPP5).
*
* @param element
* @return The XmlElement (XPP5) converted.
*/
public static org.xmlpull.infoset.XmlElement xmlElement3ToXmlElement5(org.xmlpull.v1.builder.XmlElement element) {
String string = xmlElementToString(element);
return stringToXmlElement(string);
}
/**
* Converts a specified XmlElement (XPP5) to the XmlElement (XPP3).
*
* @param element
* @return The XmlElement (XPP3) converted.
*/
public static org.xmlpull.v1.builder.XmlElement xmlElement5ToXmlElement3(org.xmlpull.infoset.XmlElement element) {
String string = xmlElementToString(element);
return stringToXmlElement3(string);
}
/**
* Returns the XML string of a specified XmlElement.
*
* @param element
* The specified XmlElement
* @return The XML string
*/
public static String xmlElementToString(org.xmlpull.v1.builder.XmlElement element) {
MXSerializer serializer = new MXSerializer();
StringWriter writer = new StringWriter();
serializer.setOutput(writer);
serializer.setProperty(PROPERTY_SERIALIZER_INDENTATION, INDENT);
BUILDER3.serialize(element, serializer);
String xmlText = writer.toString();
return xmlText;
}
/**
* Returns the XML string as a specified XmlElement (XPP5).
*
* @param element
* The specified XmlElement
* @return The XML string
*/
public static String xmlElementToString(org.xmlpull.infoset.XmlElement element) {
String string;
if (element == null) {
string = "";
} else {
string = BUILDER.serializeToStringPretty(element);
}
return string;
}
/**
* Converts a specified XPP5 XML element to a DOM element under a specified document.
*
* @param xppElement
* @param document
* @return The converted DOM element.
*/
public static Element xppElementToDomElement(org.xmlpull.infoset.XmlElement xppElement, Document document) {
Element domElement = document.createElement(xppElement.getName());
for (org.xmlpull.infoset.XmlNamespace namespace : xppElement.namespaces()) {
logger.debug("namespace: " + namespace);
}
for (org.xmlpull.infoset.XmlAttribute attribute : xppElement.attributes()) {
domElement.setAttribute(attribute.getName(), attribute.getValue());
}
for (Object object : xppElement.children()) {
if (object instanceof org.xmlpull.infoset.XmlElement) {
domElement.appendChild(xppElementToDomElement((org.xmlpull.infoset.XmlElement) object, document));
} else if (object instanceof String) {
Text text = document.createTextNode((String) object);
domElement.appendChild(text);
} else {
logger.debug("object.getClass(): " + object.getClass());
}
}
return domElement;
}
// /**
// * @param definitions3
// * @return The WsdlDefinitions (XSUL5)
// */
// @Deprecated
// public static xsul5.wsdl.WsdlDefinitions wsdlDefinitions3ToWsdlDefintions5(xsul.wsdl.WsdlDefinitions definitions3) {
// return WSDLUtil.wsdlDefinitions3ToWsdlDefintions5(definitions3);
// }
//
// /**
// * @param definitions5
// * @return The WsdlDefinitions (XSUL3)
// */
// @Deprecated
// public static xsul.wsdl.WsdlDefinitions wsdlDefinitions5ToWsdlDefintions3(xsul5.wsdl.WsdlDefinitions definitions5) {
// return WSDLUtil.wsdlDefinitions5ToWsdlDefintions3(definitions5);
// }
/**
* Converts a specified XPP3 XML element to a DOM element under a specified document.
*
* @param xppElement
* @param document
* @return The converted DOM element.
*/
public static Element xppElementToDomElement(org.xmlpull.v1.builder.XmlElement xppElement, Document document) {
Element domElement = document.createElement(xppElement.getName());
Iterator nsIt = xppElement.namespaces();
while (nsIt.hasNext()) {
org.xmlpull.v1.builder.XmlNamespace namespace = (org.xmlpull.v1.builder.XmlNamespace) nsIt.next();
logger.debug("namespace: " + namespace);
// TODO
}
Iterator attrIt = xppElement.attributes();
while (attrIt.hasNext()) {
org.xmlpull.v1.builder.XmlAttribute attribute = (org.xmlpull.v1.builder.XmlAttribute) attrIt.next();
// TODO namespace
domElement.setAttribute(attribute.getName(), attribute.getValue());
}
Iterator elementIt = xppElement.children();
while (elementIt.hasNext()) {
Object object = elementIt.next();
if (object instanceof org.xmlpull.v1.builder.XmlElement) {
domElement.appendChild(xppElementToDomElement((org.xmlpull.v1.builder.XmlElement) object, document));
} else if (object instanceof String) {
Text text = document.createTextNode((String) object);
domElement.appendChild(text);
} else {
logger.debug("object.getClass(): " + object.getClass());
}
}
return domElement;
}
/**
* @param element
* @return The cloned XmlElement.
*/
public static org.xmlpull.infoset.XmlElement deepClone(org.xmlpull.infoset.XmlElement element)
throws AiravataException {
try {
XmlElement clonedElement = element.clone();
clonedElement.setParent(null);
return clonedElement;
} catch (CloneNotSupportedException e) {
// This should not happen because we don't put any special Objects.
throw new AiravataException(e.getMessage(), e);
}
}
/**
* Saves a specified XmlElement to a specified file.
*
* @param element
* @param file
* @throws IOException
*/
public static void saveXML(org.xmlpull.infoset.XmlElement element, File file) throws IOException {
XmlDocument document = BUILDER.newDocument();
document.setDocumentElement(element);
String xmlText = BUILDER.serializeToStringPretty(document);
IOUtil.writeToFile(xmlText, file);
}
/**
* Saves a specified XmlElement to a specified file.
*
* @param element
* @param file
* @throws IOException
*/
public static void saveXML(org.xmlpull.v1.builder.XmlElement element, File file) throws IOException {
saveXML(xmlElement3ToXmlElement5(element), file);
}
/**
* @param file
* @return The XmlElement in the document.
* @throws IOException
*/
public static org.xmlpull.infoset.XmlElement loadXML(InputStream stream) throws IOException {
String xmlText = IOUtil.readToString(stream);
XmlDocument document = BUILDER.parseString(xmlText);
return document.getDocumentElement();
}
/**
* @param file
* @return The XmlElement in the document.
* @throws IOException
*/
public static org.xmlpull.infoset.XmlElement loadXML(File file) throws IOException {
return loadXML(new FileInputStream(file));
}
/**
* @param string
* @return true if the specified string is XML, false otherwise
*/
public static boolean isXML(String string) {
try {
stringToXmlElement(string);
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Validates a specified XmlObject along with logging errors if any.
*
* @param xmlObject
*/
public static void validate(XmlObject xmlObject) throws AiravataException {
XmlOptions validateOptions = new XmlOptions();
ArrayList errorList = new ArrayList();
validateOptions.setErrorListener(errorList);
boolean isValid = xmlObject.validate(validateOptions);
if (isValid) {
// Valid
return;
}
// Error
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < errorList.size(); i++) {
XmlError error = (XmlError) errorList.get(i);
logger.warn("Message: " + error.getMessage());
logger.warn("Location of invalid XML: " + error.getCursorLocation().xmlText());
stringBuilder.append("Message:" + error.getMessage());
stringBuilder.append("Location of invalid XML: " + error.getCursorLocation().xmlText());
}
throw new AiravataException(stringBuilder.toString());
}
/**
* Returns the local part of a specified QName.
*
* @param qname
* the specified QName in string, e.g. ns:value
* @return the local part of the QName, e.g. value
*/
public static String getLocalPartOfQName(String qname) {
int index = qname.indexOf(':');
if (index < 0) {
return qname;
} else {
return qname.substring(index + 1);
}
}
/**
* Returns the prefix of a specified QName.
*
* @param qname
* the specified QName in string, e.g. ns:value
* @return the prefix of the QName, e.g. ns
*/
public static String getPrefixOfQName(String qname) {
int index = qname.indexOf(':');
if (index < 0) {
return null;
} else {
return qname.substring(0, index);
}
}
/**
* @param prefixCandidate
* @param uri
* @param alwaysUseSuffix
* @param element
* @return The namespace found or declared.
*/
public static XmlNamespace declareNamespaceIfNecessary(String prefixCandidate, String uri, boolean alwaysUseSuffix,
XmlElement element) {
XmlNamespace namespace = element.lookupNamespaceByName(uri);
if (namespace == null) {
return declareNamespace(prefixCandidate, uri, alwaysUseSuffix, element);
} else {
return namespace;
}
}
/**
* @param prefixCandidate
* @param uri
* @param alwaysUseSuffix
* @param element
* @return The namespace declared.
*/
public static XmlNamespace declareNamespace(String prefixCandidate, String uri, boolean alwaysUseSuffix,
XmlElement element) {
if (prefixCandidate == null || prefixCandidate.length() == 0) {
prefixCandidate = "a";
}
String prefix = prefixCandidate;
if (alwaysUseSuffix) {
prefix += "0";
}
if (element.lookupNamespaceByPrefix(prefix) != null) {
int i = 1;
prefix = prefixCandidate + i;
while (element.lookupNamespaceByPrefix(prefix) != null) {
i++;
}
}
XmlNamespace namespace = element.declareNamespace(prefix, uri);
return namespace;
}
/**
*
* @param xml
* @param name
*/
public static void removeElements(XmlElement xml, String name) {
Iterable<XmlElement> removeElements = xml.elements(null, name);
LinkedList<XmlElement> removeList = new LinkedList<XmlElement>();
for (XmlElement xmlElement : removeElements) {
removeList.add(xmlElement);
}
for (XmlElement xmlElement : removeList) {
xml.removeChild(xmlElement);
}
Iterable children = xml.children();
for (Object object : children) {
if (object instanceof XmlElement) {
XmlElement element = (XmlElement) object;
removeElements(element, name);
}
}
}
/**
* @param url
* @return Document
*/
public static Document retrievalXMLDocFromUrl(String url) {
try {
URL xmlUrl = new URL(url);
InputStream in = xmlUrl.openStream();
Document ret = null;
DocumentBuilderFactory domFactory;
DocumentBuilder builder;
domFactory = DocumentBuilderFactory.newInstance();
domFactory.setValidating(false);
domFactory.setNamespaceAware(false);
builder = domFactory.newDocumentBuilder();
ret = builder.parse(in);
return ret;
} catch (MalformedURLException e) {
logger.error(e.getMessage(), e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
} catch (ParserConfigurationException e) {
logger.error(e.getMessage(), e);
} catch (SAXException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* @param url
* @return Document
*/
public static Document retrievalXMLDocForParse(String url) {
try {
URL xmlUrl = new URL(url);
InputStream in = xmlUrl.openStream();
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(true);
DocumentBuilder builder = xmlFact.newDocumentBuilder();
Document doc = builder.parse(in);
return doc;
} catch (MalformedURLException e) {
logger.error("Malformed URL", e);
} catch (IOException e) {
logger.error(e.getMessage(), e);
} catch (ParserConfigurationException e) {
logger.error(e.getMessage(), e);
} catch (SAXException e) {
logger.error(e.getMessage(), e);
}
return null;
}
public static boolean isEqual(XmlElement elem1, XmlElement elem2) throws Exception {
if (elem1 == null && elem2 == null) {
return true;
} else if (elem1 == null) {
return false;
} else if (elem2 == null) {
return false;
}
if (!elem1.getName().equals(elem2.getName())) {
return false;
} else {
// now check if children are the same
Iterator children1 = elem1.children().iterator();
Iterator children2 = elem2.children().iterator();
//check first ones for string
Object child1 = null;
Object child2 = null;
if (children1.hasNext() && children2.hasNext()) {
child1 = children1.next();
child2 = children2.next();
if (!children1.hasNext() && !children2.hasNext()) {
//only one node could be string could be xmlelement
return compareObjs(child1, child2);
} else {
//get new iterators
List<XmlElement> elemSet1 = getXmlElementsOnly(elem1.children().iterator());
List<XmlElement> elemSet2 = getXmlElementsOnly(elem2.children().iterator());
if(elemSet1.size() != elemSet2.size()){
return false;
}
for(int i =0; i< elemSet1.size(); ++i){
if(!isEqual(elemSet1.get(i), elemSet2.get(i))){
return false;
}
}
return true;
}
}else {
//no internal element
return true;
}
}
}
private static List<XmlElement> getXmlElementsOnly(Iterator itr){
LinkedList<XmlElement> list = new LinkedList<XmlElement>();
while(itr.hasNext()){
Object obj = itr.next();
if(obj instanceof XmlElement){
list.add((XmlElement) obj);
}
}
return list;
}
private static boolean compareObjs(Object child1, Object child2) throws Exception {
if (child1 instanceof String && child2 instanceof String) {
return child1.equals(child2);
} else if (child1 instanceof XmlElement && child2 instanceof XmlElement) {
return isEqual((XmlElement) child1, (XmlElement) child2);
} else {
return false;
}
}
}