org.opensaml.xml.util.XMLObjectHelper Maven / Gradle / Ivy
/*
* Licensed to the University Corporation for Advanced Internet Development,
* Inc. (UCAID) under one or more contributor license agreements. See the
* NOTICE file distributed with this work for additional information regarding
* copyright ownership. The UCAID 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.opensaml.xml.util;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.Namespace;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.XMLRuntimeException;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallingException;
import org.opensaml.xml.parse.ParserPool;
import org.opensaml.xml.parse.XMLParserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* A helper class for working with XMLObjects.
*/
public final class XMLObjectHelper {
/** Constructor. */
private XMLObjectHelper() { }
/**
* Clone an XMLObject by brute force:
*
*
* 1) Marshall the original object if necessary
* 2) Clone the resulting DOM Element
* 3) Unmarshall a new XMLObject tree around it.
*
*
*
* This method variant is equivalent to cloneXMLObject(originalXMLObject, false).
*
*
*
* @param originalXMLObject the object to be cloned
* @return a clone of the original object
*
* @throws MarshallingException if original object can not be marshalled
* @throws UnmarshallingException if cloned object tree can not be unmarshalled
*
* @param the type of object being cloned
*/
public static T cloneXMLObject(T originalXMLObject)
throws MarshallingException, UnmarshallingException {
return cloneXMLObject(originalXMLObject, false);
}
/**
* Clone an XMLObject by brute force:
*
*
* 1) Marshall the original object if necessary
* 2) Clone the resulting DOM Element
* 3) Unmarshall a new XMLObject tree around it.
*
*
* @param originalXMLObject the object to be cloned
* @param rootInNewDocument if true the cloned object's cached DOM will be rooted
* in a new Document; if false, the original object's underlying DOM is cloned,
* but the cloned copy remains unrooted and owned by the original Document
* @return a clone of the original object
*
* @throws MarshallingException if original object can not be marshalled
* @throws UnmarshallingException if cloned object tree can not be unmarshalled
*
* @param the type of object being cloned
*/
public static T cloneXMLObject(T originalXMLObject, boolean rootInNewDocument)
throws MarshallingException, UnmarshallingException {
if (originalXMLObject == null) {
return null;
}
Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(originalXMLObject);
Element origElement = marshaller.marshall(originalXMLObject);
Element clonedElement = null;
if (rootInNewDocument) {
try {
Document newDocument = Configuration.getParserPool().newDocument();
// Note: importNode copies the node tree and does not modify the source document
clonedElement = (Element) newDocument.importNode(origElement, true);
newDocument.appendChild(clonedElement);
} catch (XMLParserException e) {
throw new XMLRuntimeException("Error obtaining new Document from parser pool", e);
}
} else {
clonedElement = (Element) origElement.cloneNode(true);
}
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(clonedElement);
T clonedXMLObject = (T) unmarshaller.unmarshall(clonedElement);
return clonedXMLObject;
}
/**
* Unmarshall a Document from an InputSteam.
*
* @param parserPool the ParserPool instance to use
* @param inputStream the InputStream to unmarshall
* @return the unmarshalled XMLObject
* @throws XMLParserException if there is a problem parsing the input data
* @throws UnmarshallingException if there is a problem unmarshalling the parsed DOM
*/
public static XMLObject unmarshallFromInputStream(ParserPool parserPool, InputStream inputStream)
throws XMLParserException, UnmarshallingException {
Logger log = getLogger();
log.debug("Parsing InputStream into DOM document");
Document messageDoc = parserPool.parse(inputStream);
Element messageElem = messageDoc.getDocumentElement();
if (log.isTraceEnabled()) {
log.trace("Resultant DOM message was:");
log.trace(XMLHelper.nodeToString(messageElem));
}
log.debug("Unmarshalling DOM parsed from InputStream");
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
if (unmarshaller == null) {
log.error("Unable to unmarshall InputStream, no unmarshaller registered for element "
+ XMLHelper.getNodeQName(messageElem));
throw new UnmarshallingException(
"Unable to unmarshall InputStream, no unmarshaller registered for element "
+ XMLHelper.getNodeQName(messageElem));
}
XMLObject message = unmarshaller.unmarshall(messageElem);
log.debug("InputStream succesfully unmarshalled");
return message;
}
/**
* Unmarshall a Document from a Reader.
*
* @param parserPool the ParserPool instance to use
* @param reader the Reader to unmarshall
* @return the unmarshalled XMLObject
* @throws XMLParserException if there is a problem parsing the input data
* @throws UnmarshallingException if there is a problem unmarshalling the parsed DOM
*/
public static XMLObject unmarshallFromReader(ParserPool parserPool, Reader reader)
throws XMLParserException, UnmarshallingException {
Logger log = getLogger();
log.debug("Parsing Reader into DOM document");
Document messageDoc = parserPool.parse(reader);
Element messageElem = messageDoc.getDocumentElement();
if (log.isTraceEnabled()) {
log.trace("Resultant DOM message was:");
log.trace(XMLHelper.nodeToString(messageElem));
}
log.debug("Unmarshalling DOM parsed from Reader");
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
if (unmarshaller == null) {
log.error("Unable to unmarshall Reader, no unmarshaller registered for element "
+ XMLHelper.getNodeQName(messageElem));
throw new UnmarshallingException(
"Unable to unmarshall Reader, no unmarshaller registered for element "
+ XMLHelper.getNodeQName(messageElem));
}
XMLObject message = unmarshaller.unmarshall(messageElem);
log.debug("Reader succesfully unmarshalled");
return message;
}
/**
* Marshall an XMLObject. If the XMLObject already has a cached DOM via {@link XMLObject#getDOM()},
* that Element will be returned. Otherwise the object will be fully marshalled and that Element returned.
*
* @param xmlObject the XMLObject to marshall
* @return the marshalled Element
* @throws MarshallingException if there is a problem marshalling the XMLObject
*/
public static Element marshall(XMLObject xmlObject) throws MarshallingException {
Logger log = getLogger();
log.debug("Marshalling XMLObject");
if (xmlObject.getDOM() != null) {
log.debug("XMLObject already had cached DOM, returning that element");
return xmlObject.getDOM();
}
Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(xmlObject);
if (marshaller == null) {
log.error("Unable to marshall XMLOBject, no marshaller registered for object: "
+ xmlObject.getElementQName());
}
Element messageElem = marshaller.marshall(xmlObject);
if (log.isTraceEnabled()) {
log.trace("Marshalled XMLObject into DOM:");
log.trace(XMLHelper.nodeToString(messageElem));
}
return messageElem;
}
/**
* Marshall an XMLObject to an OutputStream.
*
* @param xmlObject the XMLObject to marshall
* @param outputStream the OutputStream to which to marshall
* @throws MarshallingException if there is a problem marshalling the object
*/
public static void marshallToOutputStream(XMLObject xmlObject, OutputStream outputStream)
throws MarshallingException {
Element element = marshall(xmlObject);
XMLHelper.writeNode(element, outputStream);
}
/**
* Marshall an XMLObject to a Writer.
*
* @param xmlObject the XMLObject to marshall
* @param writer the Writer to which to marshall
* @throws MarshallingException if there is a problem marshalling the object
*/
public static void marshallToWriter(XMLObject xmlObject, Writer writer) throws MarshallingException {
Element element = marshall(xmlObject);
XMLHelper.writeNode(element, writer);
}
/**
* Get the namespace URI bound to the specified prefix within the scope of the specified
* XMLObject.
*
* @param xmlObject the XMLObject from which to search
* @param prefix the prefix to search
* @return the namespace URI bound to the prefix, or none if not found
*/
public static String lookupNamespaceURI(XMLObject xmlObject, String prefix) {
XMLObject current = xmlObject;
while (current != null) {
for (Namespace ns : current.getNamespaces()) {
if (DatatypeHelper.safeEquals(ns.getNamespacePrefix(), prefix)) {
return ns.getNamespaceURI();
}
}
current = current.getParent();
}
return null;
}
/**
* Get the prefix bound to the specified namespace URI within the scope of the specified
* XMLObject.
*
* @param xmlObject the XMLObject from which to search
* @param namespaceURI the namespace URI to search
* @return the prefix bound to the namespace URI, or none if not found
*/
public static String lookupNamespacePrefix(XMLObject xmlObject, String namespaceURI) {
XMLObject current = xmlObject;
while (current != null) {
for (Namespace ns : current.getNamespaces()) {
if (DatatypeHelper.safeEquals(ns.getNamespaceURI(), namespaceURI)) {
return ns.getNamespacePrefix();
}
}
current = current.getParent();
}
return null;
}
/**
* Get an SLF4J Logger.
*
* @return a Logger instance
*/
private static Logger getLogger() {
return LoggerFactory.getLogger(XMLObjectHelper.class);
}
}