blob: 993063c3f4134666b0867f3470a6e6ca63765948 [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.axiom.om.util;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMComment;
import org.apache.axiom.om.OMContainer;
import org.apache.axiom.om.OMDataSource;
import org.apache.axiom.om.OMDataSourceExt;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMSourcedElement;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPFault;
import org.apache.axiom.soap.SOAPFaultCode;
import org.apache.axiom.soap.SOAPFaultDetail;
import org.apache.axiom.soap.SOAPFaultNode;
import org.apache.axiom.soap.SOAPFaultReason;
import org.apache.axiom.soap.SOAPFaultRole;
import org.apache.axiom.soap.SOAPFaultSubCode;
import org.apache.axiom.soap.SOAPFaultText;
import org.apache.axiom.soap.SOAPFaultValue;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.util.Iterator;
/**
* CopyUtils provides static utility methods that are useful for creating a copy of
* an OM/SOAPEnvelope tree.
* During the expansion, the Source tree retains its shape
* (OMSourcedElement nodes are not expanded).
* The Target tree has nodes that retain the class identity of the source node. For
* example, a SOAPFault in the source tree will have a SOAPFault in the target tree.
*/
public class CopyUtils {
private static final Log log = LogFactory.getLog(CopyUtils.class);
/**
* Private Constructor
*/
private CopyUtils() {
}
/**
* Creates a copy of the source envelope.
* If there are OMSourcedElements in the source tree,
* similar MSourcedElements are used in the target tree.
*
* @param sourceEnv
* @return targetEnv
*/
public static SOAPEnvelope copy(SOAPEnvelope sourceEnv) {
// Make sure to build the whole sourceEnv
if (log.isDebugEnabled()) {
log.debug("start copy SOAPEnvelope");
}
SOAPFactory factory = (SOAPFactory) sourceEnv.getOMFactory();
// Create envelope with the same prefix
SOAPEnvelope targetEnv = factory.createSOAPEnvelope(sourceEnv.getNamespace());
// Copy the attributes and namespaces from the source
// envelope to the target envelope.
copyTagData(sourceEnv, targetEnv);
Iterator i = sourceEnv.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
if (node instanceof SOAPHeader) {
// Copy the SOAPHeader tree
SOAPHeader targetHeader = factory.createSOAPHeader(targetEnv);
Iterator j = ((SOAPHeader)node).getChildren();
while (j.hasNext()) {
OMNode child = (OMNode) j.next();
copy(factory, targetHeader, child);
}
} else if (node instanceof SOAPBody) {
// Copy the SOAPBody tree
SOAPBody targetBody = factory.createSOAPBody(targetEnv);
Iterator j = ((SOAPBody)node).getChildren();
while (j.hasNext()) {
OMNode child = (OMNode) j.next();
copy(factory, targetBody, child);
}
} else {
// Comments, text, etc.
copy(factory, targetEnv, node);
}
}
if (log.isDebugEnabled()) {
log.debug("end copy SOAPEnvelope");
}
return targetEnv;
}
/**
* Simple utility that takes an XMLStreamReader and writes it
* to an XMLStreamWriter
* @param reader
* @param writer
* @throws XMLStreamException
*/
public static void reader2writer(XMLStreamReader reader,
XMLStreamWriter writer)
throws XMLStreamException {
StAXOMBuilder builder = new StAXOMBuilder(reader);
builder.releaseParserOnClose(true);
try {
OMDocument omDocument = builder.getDocument();
Iterator it = omDocument.getChildren();
while (it.hasNext()) {
OMNode omNode = (OMNode) it.next();
omNode.serializeAndConsume(writer);
}
} finally {
builder.close();
}
}
/**
* Create a copy of the sourceNode and attach it to the targetParent
* @param factory OMFactory
* @param targetParent
* @param sourceNode
*/
private static void copy(SOAPFactory factory,
OMContainer targetParent,
OMNode sourceNode) {
// Create and attach a node of the same class
// TODO It would be nice if you could do this directly from the
// OMNode, but OMNode.clone() does not gurantee that an object of the correct
// class is created.
if (sourceNode instanceof SOAPHeaderBlock) {
copySOAPHeaderBlock(factory, targetParent, (SOAPHeaderBlock) sourceNode);
} else if (sourceNode instanceof SOAPFault) {
copySOAPFault(factory, targetParent, (SOAPFault) sourceNode);
} else if (sourceNode instanceof OMSourcedElement) {
copyOMSourcedElement(factory, targetParent, (OMSourcedElement) sourceNode);
} else if (sourceNode instanceof OMElement) {
copyOMElement(factory, targetParent, (OMElement) sourceNode);
} else if (sourceNode instanceof OMText) {
copyOMText(factory, targetParent, (OMText) sourceNode);
} else if (sourceNode instanceof OMComment) {
copyOMComment(factory, targetParent, (OMComment) sourceNode);
} else {
throw new OMException("Internal Failure: Cannot make a copy of "
+ sourceNode.getClass().getName());
}
}
/**
* Create a copy of the source OMComment
* @param factory
* @param targetParent
* @param sourceComment
*/
private static void copyOMComment(SOAPFactory factory,
OMContainer targetParent,
OMComment sourceComment) {
// Create and attach the comment
factory.createOMComment(targetParent, sourceComment.getValue());
}
/**
* Create a copy of the OM Text
* @param factory
* @param targetParent
* @param sourceText
*/
private static void copyOMText(SOAPFactory factory,
OMContainer targetParent,
OMText sourceText) {
if (log.isDebugEnabled()) {
log.debug("start copyOMText");
}
if (sourceText.isBinary()) {
// This forces a load of the datahandler so that it is saved on the copy.
Object dh = sourceText.getDataHandler();
if (log.isDebugEnabled()) {
String dhclass = (dh == null) ? "null" : dh.getClass().toString();
log.debug("The source text's binary data handler is " + dhclass);
}
}
factory.createOMText(targetParent, sourceText);
if (log.isDebugEnabled()) {
log.debug("end copyOMText");
}
}
/**
* Create a copy of an ordinary OMElement
* @param factory
* @param targetParent
* @param sourceElement
*/
private static void copyOMElement(SOAPFactory factory,
OMContainer targetParent,
OMElement sourceElement) {
// Clone and attach the OMElement.
// REVIEW This clone will expand the underlying tree. We may want consider traversing
// a few levels deeper to see if there are any additional OMSourcedElements.
targetParent.addChild(sourceElement.cloneOMElement());
}
/**
* Create a copy of the OMSourcedElement
* @param factory
* @param targetParent
* @param sourceOMSE
*/
private static void copyOMSourcedElement(SOAPFactory factory,
OMContainer targetParent,
OMSourcedElement sourceOMSE) {
// If already expanded or this is not an OMDataSourceExt, then
// create a copy of the OM Tree
OMDataSource ds = sourceOMSE.getDataSource();
if (ds == null ||
sourceOMSE.isExpanded() ||
!(ds instanceof OMDataSourceExt)) {
copyOMElement(factory, targetParent, sourceOMSE);
return;
}
// If copying is destructive, then copy the OM tree
OMDataSourceExt sourceDS = (OMDataSourceExt) ds;
if (sourceDS.isDestructiveRead() ||
sourceDS.isDestructiveWrite()) {
copyOMElement(factory, targetParent, sourceOMSE);
return;
}
OMDataSourceExt targetDS = ((OMDataSourceExt) ds).copy();
if (targetDS == null) {
copyOMElement(factory, targetParent, sourceOMSE);
return;
}
// Otherwise create a target OMSE with the copied DataSource
OMSourcedElement targetOMSE =
factory.createOMElement(targetDS,
sourceOMSE.getLocalName(),
sourceOMSE.getNamespace());
targetParent.addChild(targetOMSE);
}
/**
* Create a copy of the SOAPHeaderBlock
* @param factory
* @param targetParent
* @param sourceSHB
*/
private static void copySOAPHeaderBlock(SOAPFactory factory,
OMContainer targetParent,
SOAPHeaderBlock sourceSHB) {
// If already expanded or this is not an OMDataSourceExt, then
// create a copy of the OM Tree
OMDataSource ds = sourceSHB.getDataSource();
if (ds == null ||
sourceSHB.isExpanded() ||
!(ds instanceof OMDataSourceExt)) {
copySOAPHeaderBlock_NoDataSource(factory, targetParent, sourceSHB);
return;
}
// If copying is destructive, then copy the OM tree
OMDataSourceExt sourceDS = (OMDataSourceExt) ds;
if (sourceDS.isDestructiveRead() ||
sourceDS.isDestructiveWrite()) {
copySOAPHeaderBlock_NoDataSource(factory, targetParent, sourceSHB);
return;
}
// Otherwise create a copy of the OMDataSource
OMDataSourceExt targetDS = ((OMDataSourceExt) ds).copy();
SOAPHeaderBlock targetSHB =
factory.createSOAPHeaderBlock(sourceSHB.getLocalName(),
sourceSHB.getNamespace(),
targetDS);
targetParent.addChild(targetSHB);
copySOAPHeaderBlockData(sourceSHB, targetSHB);
}
/**
* Create a copy of the SOAPHeaderBlock
* @param factory
* @param targetParent
* @param sourceSHB
*/
private static void copySOAPHeaderBlock_NoDataSource(SOAPFactory factory,
OMContainer targetParent,
SOAPHeaderBlock sourceSHB) {
SOAPHeader header = (SOAPHeader) targetParent;
String localName = sourceSHB.getLocalName();
OMNamespace ns = sourceSHB.getNamespace();
SOAPHeaderBlock targetSHB = factory.createSOAPHeaderBlock(localName, ns, header);
// A SOAPHeaderBlock has tag data, plus extra header processing flags
copyTagData(sourceSHB, targetSHB);
copySOAPHeaderBlockData(sourceSHB, targetSHB);
Iterator i = sourceSHB.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
copy(factory, targetSHB, node);
}
}
/**
* Create a copy of a SOAPFault
* @param factory
* @param targetParent
* @param sourceSOAPFault
*/
private static void copySOAPFault(SOAPFactory factory,
OMContainer targetParent,
SOAPFault sourceSOAPFault) {
Exception e = sourceSOAPFault.getException();
SOAPFault newSOAPFault = (e == null) ?
factory.createSOAPFault((SOAPBody) targetParent):
factory.createSOAPFault((SOAPBody) targetParent, e);
copyTagData(sourceSOAPFault, newSOAPFault);
Iterator i = sourceSOAPFault.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
// Copy the tree under the SOAPFault
copyFaultData(factory, newSOAPFault, node);
}
}
/**
* Copy the source Node, which is a child fo a SOAPFault,
* to the target SOAPFault
* @param factory
* @param targetFault
* @param sourceNode
*/
private static void copyFaultData(SOAPFactory factory,
SOAPFault targetFault,
OMNode sourceNode) {
if (sourceNode instanceof SOAPFaultCode) {
copySOAPFaultCode(factory, targetFault, (SOAPFaultCode) sourceNode);
} else if (sourceNode instanceof SOAPFaultDetail) {
copySOAPFaultDetail(factory, targetFault, (SOAPFaultDetail) sourceNode);
} else if (sourceNode instanceof SOAPFaultNode) {
copySOAPFaultNode(factory, targetFault, (SOAPFaultNode) sourceNode);
} else if (sourceNode instanceof SOAPFaultReason) {
copySOAPFaultReason(factory, targetFault, (SOAPFaultReason) sourceNode);
} else if (sourceNode instanceof SOAPFaultRole) {
copySOAPFaultRole(factory, targetFault, (SOAPFaultRole) sourceNode);
} else if (sourceNode instanceof OMText) {
copyOMText(factory, targetFault, (OMText) sourceNode);
} else if (sourceNode instanceof OMComment) {
copyOMComment(factory, targetFault, (OMComment) sourceNode);
} else {
throw new OMException("Internal Failure: Cannot make a copy of "
+ sourceNode.getClass().getName() + " object found in a SOAPFault.");
}
}
/**
* Create a copy of a SOAPFaultRole
* @param factory
* @param targetFault
* @param sourceRole
*/
private static void copySOAPFaultRole(SOAPFactory factory,
SOAPFault targetFault,
SOAPFaultRole sourceRole) {
SOAPFaultRole targetRole = factory.createSOAPFaultRole(targetFault);
copyTagData(sourceRole, targetRole);
targetRole.setRoleValue(sourceRole.getRoleValue());
}
/**
* Create a copy of a SOAPFaultNode
* @param factory
* @param targetFault
* @param sourceNode
*/
private static void copySOAPFaultNode(SOAPFactory factory,
SOAPFault targetFault,
SOAPFaultNode sourceNode) {
SOAPFaultNode targetNode = factory.createSOAPFaultNode(targetFault);
copyTagData(sourceNode, targetNode);
targetNode.setFaultNodeValue(sourceNode.getFaultNodeValue());
}
/**
* Create a copy of a SOAPFaultDetail
* @param factory
* @param targetFault
* @param sourceDetail
*/
private static void copySOAPFaultDetail(SOAPFactory factory,
SOAPFault targetFault,
SOAPFaultDetail sourceDetail) {
SOAPFaultDetail targetDetail = factory.createSOAPFaultDetail(targetFault);
copyTagData(sourceDetail, targetDetail);
// Copy the detail entries
Iterator i = sourceDetail.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
copy(factory, targetDetail, node);
}
}
/**
* Create a copy of the SOAPFaultReason
* @param factory
* @param targetFault
* @param sourceReason
*/
private static void copySOAPFaultReason(SOAPFactory factory,
SOAPFault targetFault,
SOAPFaultReason sourceReason) {
SOAPFaultReason targetReason = factory.createSOAPFaultReason(targetFault);
copyTagData(sourceReason, targetReason);
Iterator i = sourceReason.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
if (node instanceof SOAPFaultText) {
SOAPFaultText oldText = (SOAPFaultText) node;
SOAPFaultText newText = factory.createSOAPFaultText(targetReason);
copyTagData(oldText, newText); // The lang is copied as an attribute
} else {
// Copy any comments or child nodes
copy(factory, targetReason, node);
}
}
}
/**
* Copy the SOAPFaultCode tree
* @param factory
* @param targetFault
* @param sourceCode
*/
private static void copySOAPFaultCode(SOAPFactory factory,
SOAPFault targetFault,
SOAPFaultCode sourceCode) {
SOAPFaultCode targetCode = factory.createSOAPFaultCode(targetFault);
copyTagData(sourceCode, targetCode);
// Create the Value
SOAPFaultValue sourceValue = sourceCode.getValue();
SOAPFaultValue targetValue = factory.createSOAPFaultValue(targetCode);
copyTagData(sourceValue, targetValue);
// There should only be a text node for the value, but in case there is more
Iterator i = sourceValue.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
copy(factory, targetValue, node);
}
// Now get process the SubCode
SOAPFaultSubCode sourceSubCode = sourceCode.getSubCode();
if (sourceSubCode != null) {
copySOAPFaultSubCode(factory, targetCode, sourceSubCode);
}
}
/**
* Copy the SOAPFaultSubCode tree
* @param factory
* @param targetParent (SOAPFaultCode or SOAPFaultSubCode)
* @param sourceSubCode
*/
private static void copySOAPFaultSubCode(SOAPFactory factory,
OMElement targetParent,
SOAPFaultSubCode sourceSubCode) {
SOAPFaultSubCode targetSubCode;
if (targetParent instanceof SOAPFaultSubCode) {
targetSubCode = factory.createSOAPFaultSubCode((SOAPFaultSubCode) targetParent);
} else {
targetSubCode = factory.createSOAPFaultSubCode((SOAPFaultCode) targetParent);
}
copyTagData(sourceSubCode, targetSubCode);
// Process the SOAP FaultValue
SOAPFaultValue sourceValue = sourceSubCode.getValue();
SOAPFaultValue targetValue = factory.createSOAPFaultValue(targetSubCode);
copyTagData(sourceValue, targetValue);
// There should only be a text node for the value, but in case there is more
Iterator i = sourceValue.getChildren();
while (i.hasNext()) {
OMNode node = (OMNode) i.next();
copy(factory, targetValue, node);
}
// Now process the SubCode of the SubCode
SOAPFaultSubCode sourceSubSubCode = sourceSubCode.getSubCode();
if (sourceSubSubCode != null) {
copySOAPFaultSubCode(factory, targetSubCode, sourceSubSubCode);
}
}
/**
* Copy the tag data (attributes and namespaces) from the source
* element to the target element.
* @param sourceElement
* @param targetElement
*/
private static void copyTagData(OMElement sourceElement,
OMElement targetElement) {
for (Iterator i = sourceElement.getAllDeclaredNamespaces(); i.hasNext();) {
OMNamespace ns = (OMNamespace) i.next();
targetElement.declareNamespace(ns);
}
for (Iterator i = sourceElement.getAllAttributes(); i.hasNext();) {
OMAttribute attr = (OMAttribute) i.next();
targetElement.addAttribute(attr);
}
}
/**
* Copy Header data (currently only the processed flag) from the
* source SOAPHeaderBlock to the target SOAPHeaderBlock
* @param sourceSHB
* @param targetSHB
*/
private static void copySOAPHeaderBlockData(SOAPHeaderBlock sourceSHB,
SOAPHeaderBlock targetSHB) {
// Copy the processed flag. The other SOAPHeaderBlock information
//(e.g. role, mustUnderstand) are attributes on the tag and are copied in copyTagData.
if (sourceSHB.isProcessed()) {
targetSHB.setProcessed();
}
}
}