/* * 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 } }