blob: a3e868d328cf8ca602cdb8db1ff1fb90de5feb4e [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.axis2.jaxws.handler;
import org.apache.axiom.om.util.StAXUtils;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.message.Block;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
import org.apache.axis2.jaxws.message.factory.BlockFactory;
import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
import org.apache.axis2.jaxws.message.factory.MessageFactory;
import org.apache.axis2.jaxws.message.factory.SourceBlockFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.bind.JAXBContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.LogicalMessage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
public class LogicalMessageImpl implements LogicalMessage {
private static final Log log = LogFactory.getLog(LogicalMessageImpl.class);
private MEPContext mepCtx;
protected LogicalMessageImpl(MEPContext m) {
mepCtx = m;
}
/*
* (non-Javadoc)
* @see javax.xml.ws.LogicalMessage#getPayload()
*/
public Source getPayload() {
BlockFactory factory = (SourceBlockFactory) FactoryRegistry.getFactory(SourceBlockFactory.class);
Source payload = (Source) _getPayload(null, factory);
return payload;
}
/*
* (non-Javadoc)
* @see javax.xml.ws.LogicalMessage#getPayload(javax.xml.bind.JAXBContext)
*/
public Object getPayload(JAXBContext context) {
if (log.isDebugEnabled()) {
log.debug("Retreiving the message payload as a Source object");
}
BlockFactory factory = (JAXBBlockFactory) FactoryRegistry.getFactory(JAXBBlockFactory.class);
JAXBBlockContext jbc = new JAXBBlockContext(context);
Object payload = _getPayload(jbc, factory);
return payload;
}
private Object _getPayload(Object context, BlockFactory factory) {
Object payload = null;
try {
Block block = mepCtx.getMessageObject().getBodyBlock(context, factory);
if (block != null) {
if (log.isDebugEnabled()) {
log.debug("A message payload was found.");
}
Object content = block.getBusinessObject(true);
// For now, we have to create a new Block from the original content
// and set that back on the message. The Block is not currently
// able to create a copy of itself just yet.
Payloads payloads = createPayloads(content);
_setPayload(payloads.CACHE_PAYLOAD, context, factory);
payload = payloads.HANDLER_PAYLOAD;
}
else {
// If the block was null, then let's return an empty
// Source object rather than a null.
if (log.isDebugEnabled()) {
log.debug("There was no payload to be found. Returning an empty Source object");
}
byte[] bytes = new byte[0];
payload = new StreamSource(new ByteArrayInputStream(bytes));
}
} catch (XMLStreamException e) {
throw ExceptionFactory.makeWebServiceException(e);
}
return payload;
}
/*
* (non-Javadoc)
* @see javax.xml.ws.LogicalMessage#setPayload(java.lang.Object, javax.xml.bind.JAXBContext)
*/
public void setPayload(Object obj, JAXBContext context) {
BlockFactory factory = (JAXBBlockFactory) FactoryRegistry.getFactory(JAXBBlockFactory.class);
JAXBBlockContext jbc = new JAXBBlockContext(context);
_setPayload(obj, jbc, factory);
}
/*
* (non-Javadoc)
* @see javax.xml.ws.LogicalMessage#setPayload(javax.xml.transform.Source)
*/
public void setPayload(Source source) {
BlockFactory factory = (SourceBlockFactory) FactoryRegistry.getFactory(SourceBlockFactory.class);
_setPayload(source, null, factory);
}
private void _setPayload(Object object, Object context, BlockFactory factory) {
Block block = factory.createFrom(object, context, null);
if (mepCtx.getMessageObject() != null) {
if (!mepCtx.getMessageObject().isFault()) {
mepCtx.getMessageObject().setBodyBlock(block);
}
else {
if (log.isDebugEnabled()) {
log.debug("The payload contains a fault");
}
mepCtx.getMessageObject().setBodyBlock(block);
// If the payload is a fault, then we can't set it back on the message
// as a block. Blocks are OMSourcedElements, and faults cannot be OMSourcedElements.
try {
SOAPEnvelope env = (SOAPEnvelope) mepCtx.getMessageObject().getAsOMElement();
String content = env.toStringWithConsume();
MessageFactory mf = (MessageFactory) FactoryRegistry.getFactory(MessageFactory.class);
StringReader sr = new StringReader(content);
XMLStreamReader stream = StAXUtils.createXMLStreamReader(sr);
Message msg = mf.createFrom(stream, mepCtx.getMessageObject().getProtocol());
// This is required for proper serialization of the OM structure.
msg.getAsOMElement().build();
mepCtx.setMessage(msg);
} catch (Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
}
}
private Payloads createPayloads(Object content) {
if (content == null) {
return null;
}
Payloads payloads = new Payloads();
if (Source.class.isAssignableFrom(content.getClass())) {
try {
Transformer trans = TransformerFactory.newInstance().newTransformer();
// First we have to get the content out of the original
// Source object so we can build the cache from there.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamResult result = new StreamResult(baos);
Source source = (Source) content;
trans.transform(source, result);
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
byte[] bytes = baos.toByteArray();
// Given that we've consumed the original Source object,
// we need to create another one with the original content
// and assign it back.
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
try {
// The Source object returned to the handler should be a
// DOMSource so that the handler programmer can read the data
// multiple times and (as opposed to using a StreamSource) and
// they can more easily access the data in DOM form.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(bais);
payloads.HANDLER_PAYLOAD = new DOMSource(dom);
} catch (ParserConfigurationException e) {
throw ExceptionFactory.makeWebServiceException(e);
} catch (IOException e) {
throw ExceptionFactory.makeWebServiceException(e);
} catch (SAXException e) {
throw ExceptionFactory.makeWebServiceException(e);
}
// We need a different byte[] for the cache so that we're not just
// building two Source objects that point to the same array.
byte[] cacheBytes = new byte[bytes.length];
System.arraycopy(bytes, 0, cacheBytes, 0, bytes.length);
// Now build the Soure object for the cache.
ByteArrayInputStream cacheBais = new ByteArrayInputStream(cacheBytes);
payloads.CACHE_PAYLOAD = new StreamSource(cacheBais);
} catch (TransformerConfigurationException e) {
throw ExceptionFactory.makeWebServiceException(e);
} catch (TransformerFactoryConfigurationError e) {
throw ExceptionFactory.makeWebServiceException(e);
} catch (TransformerException e) {
throw ExceptionFactory.makeWebServiceException(e);
}
} else {
// no cache implemented yet
payloads.HANDLER_PAYLOAD = content;
payloads.CACHE_PAYLOAD = content;
}
return payloads;
}
/*
* A simple holder for the different payload objects.
*/
class Payloads {
Object HANDLER_PAYLOAD; // The payload object that will be returned to the handler
Object CACHE_PAYLOAD; // The payload object that will be used for the cache
}
}