blob: dc0362dbb4abdf738d1dbd244afead362b254f78 [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
* Copyright 2006 International Business Machines Corp.
*
* Licensed 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.axis2.jaxws.message.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory;
import org.apache.axiom.soap.impl.llom.soap12.SOAP12Factory;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.MessageException;
import org.apache.axis2.jaxws.message.MessageInternalException;
import org.apache.axis2.jaxws.message.Protocol;
import org.apache.axis2.jaxws.message.factory.BlockFactory;
import org.apache.axis2.jaxws.message.factory.OMBlockFactory;
import org.apache.axis2.jaxws.message.util.Reader2Writer;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
/**
* XMLSpineImpl
*
* An XMLSpine consists of an OM SOAPEnvelope which defines the "spine" of the message
* (i.e. the SOAPEnvelope element, the SOAPHeader element, the SOAPBody element and
* perhaps the SOAPFault element). The real payload portions of the message are
* contained in Block object (headerBlocks, bodyBlocks, detailBlocks).
*
* This "shortened" OM tree allows the JAX-WS implementation to process the message
* without creating fully populated OM trees.
*
*/
class XMLSpineImpl implements XMLSpine {
private static OMBlockFactory obf = (OMBlockFactory) FactoryRegistry.getFactory(OMBlockFactory.class);
private Protocol protocol = Protocol.unknown;
private SOAPEnvelope root = null;
private SOAPFactory soapFactory = null;
private List<Block> headerBlocks = new ArrayList<Block>();
private List<Block> bodyBlocks = new ArrayList<Block>();
private List<Block> detailBlocks = new ArrayList<Block>();
private boolean consumed = false;
private Iterator bodyIterator = null;
private Message parent;
/**
* Create a lightweight representation of this protocol
* (i.e. the Envelope, Header and Body)
*/
public XMLSpineImpl(Protocol protocol) {
super();
this.protocol = protocol;
soapFactory = getFactory(protocol);
root = createEmptyEnvelope(protocol, soapFactory);
}
/**
* Create spine from an existing OM tree
* @param envelope
* @throws MessageException
*/
public XMLSpineImpl(SOAPEnvelope envelope) throws MessageException {
super();
init(envelope);
if (root.getNamespace().getName().equals(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
protocol = Protocol.soap11;
} else if (root.getNamespace().getName().equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
protocol = Protocol.soap12;
} else {
// TODO Support for REST
throw ExceptionFactory.makeMessageInternalException(Messages.getMessage("RESTIsNotSupported"), null);
}
}
private void init(SOAPEnvelope envelope) throws MessageException {
root = envelope;
headerBlocks.clear();
bodyBlocks.clear();
detailBlocks.clear();
bodyIterator = null;
// If a header block exists, create an OMBlock for each element
// This advances the StAX parser past the header end tag
SOAPHeader header = root.getHeader();
if (header != null) {
Iterator it = header.getChildren();
advanceIterator(it, headerBlocks, true);
}
SOAPBody body = root.getBody();
if (!body.hasFault()) {
// Normal processing
// Only create the first body block, this ensures that the StAX
// cursor is not advanced beyond the tag of the first element
bodyIterator = body.getChildren();
advanceIterator(bodyIterator, bodyBlocks, false);
} else {
// Process the Fault
// TODO Add Fault Processing
throw ExceptionFactory.makeMessageException(Messages.getMessage("SOAPFaultIsNotImplemented"));
}
return;
}
/**
* Utility method to advance the iterator and populate the blocks
* @param it Iterator
* @param blocks List<Block> to update
* @param toEnd if true, iterator is advanced to the end, otherwise it is advanced one Element
* @throws MessageException
*/
private void advanceIterator(Iterator it, List<Block> blocks, boolean toEnd) throws MessageException {
// TODO This code must be reworked. The OM Iterator causes the entire OMElement to be
// parsed when it.next() is invoked. I will need to fix this to gain performance. (scheu)
boolean found = false;
boolean first = true;
while (it.hasNext() && (!found && !toEnd)) {
// Remove the nodes as they are converted into blocks
if (!first) {
it.remove();
}
first = true;
OMNode node = (OMNode) it.next();
if (node instanceof OMElement) {
// Elements are converted into Blocks
Block block = null;
try {
block = obf.createFrom((OMElement) node, null, null);
} catch (XMLStreamException xse) {
throw ExceptionFactory.makeMessageException(xse);
}
blocks.add(block);
block.setParent(this);
} else {
System.out.println("NON-ELEMENT FOUND: " + node.getClass().getName());
}
}
}
private static SOAPFactory getFactory(Protocol protocol) {
SOAPFactory soapFactory;
if (protocol == Protocol.soap11) {
soapFactory = new SOAP11Factory();
} else if (protocol == Protocol.soap12) {
soapFactory = new SOAP12Factory();
} else {
// TODO REST Support is needed
throw ExceptionFactory.makeMessageInternalException(Messages.getMessage("RESTIsNotSupported"), null);
}
return soapFactory;
}
private static SOAPEnvelope createEmptyEnvelope(Protocol protocol, SOAPFactory factory) {
SOAPEnvelope env = factory.createSOAPEnvelope();
// Add an empty body and header
factory.createSOAPBody(env);
factory.createSOAPHeader(env);
return env;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.message.XMLPart#getProtocol()
*/
public Protocol getProtocol() {
return protocol;
}
/*
* (non-Javadoc)
* @see org.apache.axis2.jaxws.message.XMLPart#getParent()
*/
public Message getParent() {
return parent;
}
/*
* Set the backpointer to this XMLPart's parent Message
*/
public void setParent(Message p) {
parent = p;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.message.XMLPart#outputTo(javax.xml.stream.XMLStreamWriter, boolean)
*/
public void outputTo(XMLStreamWriter writer, boolean consume) throws XMLStreamException, MessageException {
Reader2Writer r2w = new Reader2Writer(getXMLStreamReader(consume));
r2w.outputTo(writer);
}
public XMLStreamReader getXMLStreamReader(boolean consume) throws MessageException {
return new XMLStreamReaderForXMLSpine(root, protocol,
headerBlocks, bodyBlocks, detailBlocks, consume);
}
public boolean isConsumed() {
return consumed;
}
public javax.xml.soap.SOAPEnvelope getAsSOAPEnvelope() throws MessageException {
throw ExceptionFactory.makeMessageInternalException(Messages.getMessage("NeverCalled", "XMLSpineImpl.getAsSOAPEnvelope()"), null);
}
public OMElement getAsOMElement() throws MessageException {
throw ExceptionFactory.makeMessageInternalException(Messages.getMessage("NeverCalled", "XMLSpineImpl.getAsOMElement()"), null);
}
public Block getAsBlock(Object context, BlockFactory blockFactory) throws MessageException, XMLStreamException {
throw ExceptionFactory.makeMessageInternalException(Messages.getMessage("NeverCalled", "XMLSpineImpl.getAsBlock()"), null);
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.message.XMLPart#getNumBodyBlocks()
*/
public int getNumBodyBlocks() throws MessageException {
if (bodyIterator != null) {
advanceIterator(bodyIterator, bodyBlocks, true);
}
return bodyBlocks.size();
}
public Block getBodyBlock(int index, Object context, BlockFactory blockFactory) throws MessageException {
if (index >= bodyBlocks.size() && bodyIterator != null) {
advanceIterator(bodyIterator, bodyBlocks, true);
}
try {
Block oldBlock = bodyBlocks.get(index);
// Convert to new Block
Block newBlock = blockFactory.createFrom(oldBlock, context);
if (newBlock != oldBlock) {
bodyBlocks.set(index, newBlock);
}
return newBlock;
} catch (XMLStreamException xse) {
throw ExceptionFactory.makeMessageException(xse);
}
}
public void setBodyBlock(int index, Block block) throws MessageException {
if (index >= bodyBlocks.size() && bodyIterator != null) {
advanceIterator(bodyIterator, bodyBlocks, true);
}
bodyBlocks.add(index, block);
block.setParent(this);
}
public void removeBodyBlock(int index) throws MessageException {
if (index >= bodyBlocks.size() && bodyIterator != null) {
advanceIterator(bodyIterator, bodyBlocks, true);
}
bodyBlocks.remove(index);
}
public int getNumHeaderBlocks() throws MessageException {
return headerBlocks.size();
}
public Block getHeaderBlock(String namespace, String localPart, Object context, BlockFactory blockFactory) throws MessageException {
int index = getHeaderBlockIndex(namespace, localPart);
try {
Block oldBlock = bodyBlocks.get(index);
// Convert to new Block
Block newBlock = blockFactory.createFrom(oldBlock, context);
if (newBlock != oldBlock) {
headerBlocks.set(index, newBlock);
}
return newBlock;
} catch (XMLStreamException xse) {
throw ExceptionFactory.makeMessageException(xse);
}
}
public void setHeaderBlock(String namespace, String localPart, Block block) throws MessageException {
int index = getHeaderBlockIndex(namespace, localPart);
headerBlocks.set(index, block);
block.setParent(this);
}
/**
* Utility method to locate header block
* @param namespace
* @param localPart
* @return index of header block or -1
* @throws MessageException
*/
private int getHeaderBlockIndex(String namespace, String localPart) throws MessageException {
for (int i=0; i<headerBlocks.size(); i++) {
Block block = headerBlocks.get(i);
QName qName = block.getQName();
if (qName.getNamespaceURI().equals(namespace) &&
qName.getLocalPart().equals(localPart)) {
return i;
}
}
return -1;
}
public void removeHeaderBlock(String namespace, String localPart) throws MessageException {
int index = getHeaderBlockIndex(namespace, localPart);
headerBlocks.remove(index);
}
public String traceString(String indent) {
// TODO Trace String Support
return null;
}
}