FileDocCategorySizeDatePackage
UnWrappedMessage.javaAPI DocGlassfish v2 API40266Fri May 04 22:30:28 BST 2007com.sun.enterprise.jbi.serviceengine.comm

UnWrappedMessage.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package com.sun.enterprise.jbi.serviceengine.comm;

import com.sun.enterprise.jbi.serviceengine.core.JavaEEServiceEngineContext;
import com.sun.enterprise.jbi.serviceengine.util.DOMUtil;
import com.sun.enterprise.jbi.serviceengine.util.JBIConstants;
import com.sun.enterprise.jbi.serviceengine.util.DOMStreamReader;
import com.sun.enterprise.jbi.serviceengine.util.soap.SOAPConstants;
import com.sun.enterprise.jbi.serviceengine.util.soap.StringTranslator;
import com.sun.logging.LogDomains;
import com.sun.xml.bind.api.Bridge;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.api.message.Message;
import com.sun.enterprise.jbi.serviceengine.util.StAXSource;
import com.sun.xml.ws.message.DOMHeader;
import com.sun.xml.ws.message.DataHandlerAttachment;
import com.sun.xml.ws.message.stream.StreamHeader11;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jbi.messaging.NormalizedMessage;
import javax.wsdl.Part;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;

/**
 *
 * This class is used to unwrap the incoming JBI request message when the
 * Java EE Service Engine is the Provider.
 *
 * This class unwraps and extracts the 'payload' from the incomoming
 * request message which is in normalized form.
 *
 * The current implentation supports the following WSDL1.1 SOAP binding styles :
 *
 *      1. Wrapped Document/literal
 *      2. RPC/Literal
 *
 * The characterstics of the Wrapped Document/literal style are
 *
 *  1. The input message has a single part.
 *  2. The part is an element.
 *  3. The element has the same name as the operation.
 *  4. The element's complex type has no attributes.
 *
 * For wrapped document/literal, the incoming request message looks like :
 *
 * <?xml version="1.0" encoding="UTF-8"?>
 * <jbi:message
 *          xmlns:msgns="http://example.web.service/Calculator"
 *          name="add"
 *          type="msgns:add"
 *          version="1.0"
 *          xmlns:jbi="http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper">
 *	<jbi:part>
 *		<ns2:add xmlns:ns2="http://example.web.service/Calculator">
 *			<arg0>1.0</arg0>
 *			<arg1>2.0</arg1>
 *		</ns2:add>
 *	</jbi:part>
 * </jbi:message>
 *
 * and the payLoad node for this is :
 *
 * <ns2:add xmlns:ns2="http://example.web.service/Calculator">
 *      <arg0>1.0</arg0>
 *      <arg1>2.0</arg1>
 * </ns2:add>
 *
 * For RPC/literal, the incoming request message looks like this :
 *
 * <?xml version="1.0" encoding="UTF-8"?>
 * <jbi:message
 *          xmlns:msgns="http://example.web.service/Calculator"
 *          name="add"
 *          type="msgns:add"
 *          version="1.0"
 *          xmlns:jbi="http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper">
 *	<jbi:part><int_1>1</int_1></jbi:part>
 *	<jbi:part><int_2>2</int_2></jbi:part>
 * </jbi:message>
 *
 * and the payLoad node for this is:
 *
 * <ns2:add xmlns:ns2="http://example.web.service/Calculator">
 *      <int_1>1</int_1>
 *      <int_2>2</int_2>
 * </ns2:add>
 *
 * The styles which are not supported by JAX-WS 2.0 are:
 *      RPC/encoded
 *      Document/encoded
 *
 * The style(s) which are treated/converted as wrapped document/literal by JAX-WS tools are
 *      document/literal
 *
 * @author bhavanishankar@dev.java.net
 */

public final class UnWrappedMessage extends Message
        implements JBIConstants, SOAPConstants {
    
    private static Logger logger =
            LogDomains.getLogger(LogDomains.SERVER_LOGGER);
    
    private String payloadLocalName;
    private String payloadNamespaceURI;
    private Source payLoadAsSource;
    private XMLStreamReader payLoadAsStreamReader;
    private ByteArrayOutputStream payLoadAsBaos;
    private HeaderList headers = new HeaderList();
    private boolean isFault;
    private boolean log = false;
    
    private void setLog() {
        if(logger.isLoggable(Level.FINE)) {
            log = true;
        }
    }
    
    public UnWrappedMessage() {
        setLog();
    }
    
    /**
     * Variables used for unwrapping the message.
     */
    Source nmContent;
    NormalizedMessage normalizedMessage;
    
    QName wsdlMessageType;
    String wsdlBindingStyle;
    List<Part> wsdlOrderedParts;
    int[] wsdlPartBindings; // represents whether the part is bound to 'header', 'body', or 'attachment'.
    
    public void setNormalizedMessage(NormalizedMessage normalizedMessage) {
        this.normalizedMessage = normalizedMessage;
        this.nmContent = normalizedMessage.getContent();
    }
    
    public void setWSDLMessageType(QName wsdlMessageType) {
        this.wsdlMessageType = wsdlMessageType;
    }
    
    public void setWSDLBindingStyle(String wsdlBindingStyle) {
        this.wsdlBindingStyle = wsdlBindingStyle;
    }
    
    public void setWSDLOrderedParts(List<Part> wsdlOrderedParts) {
        this.wsdlOrderedParts = wsdlOrderedParts;
    }
    
    public void setWSDLPartBindings(int[] wsdlPartBindings) {
        this.wsdlPartBindings = wsdlPartBindings;
    }
    
    public void unwrap() throws Exception {
        
        if(log) {
            String s = (nmContent instanceof DOMSource) ? toString(nmContent) : "StreamSource";
            logger.log(Level.FINE, "bindingStyle = " + wsdlBindingStyle + ", received message = " + s);
        }
        
        if(JavaEEServiceEngineContext.getInstance().isServiceMix()) {
            if(log) {
                logger.log(Level.FINE, "Skipping the unwrapping...");
            }
            setPayLoad(nmContent);
        } else {
            if(RPC_STYLE.equalsIgnoreCase(wsdlBindingStyle)) {
                new RPCStyleUnWrapper().unwrap();
            } else {
                new DocumentStyleUnWrapper().unwrap();
            }
        }
        
        processAttachments();
        
        if(payLoadAsStreamReader == null) {
            throw new Exception(StringTranslator.getDefaultInstance().getString(
                    "serviceengine.unwrapping_failed"));
        }
        
    }
    
    public void unwrapFault() throws Exception {
        
        if(log) {
            String s = (nmContent instanceof DOMSource) ? toString(nmContent) : "StreamSource";
            logger.log(Level.FINE, "bindingStyle = " + wsdlBindingStyle + ", received fault = " + s);
        }
        
        isFault = true;
        if(JavaEEServiceEngineContext.getInstance().isServiceMix()) {
            if(log) {
                logger.log(Level.FINE, "Skipping the unwrapping...");
            }
            setPayLoad(nmContent);
        } else {
            unWrapFault();
        }
        
        if(payLoadAsStreamReader == null) {
            throw new Exception(StringTranslator.getDefaultInstance().getString(
                    "serviceengine.unwrapping_failed"));
        }
    }
    
    public boolean isFault() {
        return isFault;
    }
    
    public String getPayloadLocalPart() {
        return payloadLocalName;
    }
    
    public String getPayloadNamespaceURI() {
        return payloadNamespaceURI;
    }
    
    public boolean hasPayload() {
        return payLoadAsStreamReader == null;
    }
    
    public boolean hasHeaders() {
        return (headers.size() != 0);
    }
    
    public HeaderList getHeaders() {
        if(log) {
            logger.log(Level.FINE, "Headers = " + headers);
        }
        return headers;
    }
    
    public Message copy() {
        return null;
    }
    
    public Source readEnvelopeAsSource() {
        return null;
    }
    
    public XMLStreamReader readPayload() throws XMLStreamException {
        if(log) {
            logger.log(Level.FINE, "UnWrappedMessage :: readPayLoad()");
        }
        return payLoadAsStreamReader;
    }
    
    public Source readPayloadAsSource() {
        if(log) {
            logger.log(Level.FINE, "UnWrappedMessage :: readPayLoadAsSource()");
        }
        return payLoadAsSource;
    }
    
    public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
        return (T)unmarshaller.unmarshal(payLoadAsSource);
    }
    
    public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
        return bridge.unmarshal(payLoadAsSource);
    }
    
    public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
        throw new XMLStreamException("Operaion is not supported.");
    }
    
    public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
        throw new XMLStreamException("Operaion is not supported.");
    }
    
    public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException {
        throw new SAXException("Operaion is not supported.");
    }
    
    public SOAPMessage readAsSOAPMessage() throws SOAPException {
        String methodSig =
                "\ncom.sun.enterprise.jbi.serviceengine.comm.UnWrappedMessage" +
                "::readAsSOAPMessage()";
        String usedWith = System.getProperty(USED_WITH);
        if(usedWith == null || usedWith.indexOf(USED_WITH_JMAC_PROVIDER) == -1) {
            throw new SOAPException(
                    methodSig + " operation is not supported." +
                    "\nSet this system property to workaround this issue : " +
                    "com.sun.enterprise.jbi.se.usedwith=jmacprovider");
        }
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            XMLStreamWriter writer = XOF.createXMLStreamWriter(baos);
            writer.writeStartDocument();
            writer.writeStartElement(SOAP_ENVELOPE);
            writer.writeAttribute("xmlns:" + SOAP_PREFIX, SOAP_NAMESPACE);
            writer.writeEmptyElement(SOAP_HEADER);
            writer.writeStartElement(SOAP_BODY);
            if(payLoadAsBaos == null) {
                if(payLoadAsSource instanceof DOMSource) {
                    Node payLoadNode = ((DOMSource)payLoadAsSource).getNode();
                    DOMUtil.UTIL.writeNode(payLoadNode, writer);
                } else {
                    DOMUtil.UTIL.writeNode(payLoadAsStreamReader, writer);
                }
            } else {
                baos.write(">".getBytes());
                baos.write(payLoadAsBaos.toByteArray());
            }
            writer.writeEndElement();
            writer.writeEndElement();
            writer.writeEndDocument();
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            
            SOAPMessage message = MessageFactory.newInstance().createMessage(null, bais);
            if(log) {
                logger.log(Level.FINE, methodSig + " :: SOAPMessage = " + toString(message));
            }
            return message;
        } catch(Exception ex) {
            throw new SOAPException(methodSig + ex.getMessage());
        }
    }
    
    
    public void setPayLoad(Source s) throws Exception {
        if(s instanceof DOMSource) {
            setPayLoad(((DOMSource)s).getNode());
        } else if(s instanceof StreamSource) {
            XMLStreamReader reader = XIF.
                    createXMLStreamReader(((StreamSource)s).getInputStream());
            setPayLoad(reader);
        }  else if(s instanceof SAXSource) {
            InputSource source = ((SAXSource) s).getInputSource();
            XMLStreamReader reader = (source.getCharacterStream() != null)?
                    XIF.createXMLStreamReader(source.getCharacterStream()):
                    XIF.createXMLStreamReader(source.getByteStream());
            setPayLoad(reader);
        } else {
            logger.log(Level.WARNING, "UnWrappedMessage :: Transforming the input message to DOM");
            Transformer t = TF.newTransformer();
            DOMResult result = new DOMResult();
            t.transform(s, result);
            setPayLoad(result.getNode());
        }
    }
    
    public void setPayLoad(Node n) {
        if(n.getNodeType() == Node.DOCUMENT_NODE) {
            n = n.getFirstChild();
        }
        payloadLocalName = n.getLocalName();
        payloadNamespaceURI = n.getNamespaceURI();
        payLoadAsSource = new DOMSource(n);
        payLoadAsStreamReader = new DOMStreamReader(n);
        printPayLoad("");
    }
    
    public void setPayLoad(XMLStreamReader reader) throws Exception {
        if(reader.getEventType() == XMLStreamReader.START_DOCUMENT) {
            reader.next();
        }
        payloadLocalName =  reader.getLocalName();
        payloadNamespaceURI = reader.getNamespaceURI();
        payLoadAsSource = new StAXSource(reader, true); // StAXSource will be available in JDK6.
        payLoadAsStreamReader = reader;
        XMLStreamReader r = reader;
        printPayLoad("");
    }
    
    public void copyPayLoad(XMLStreamReader r) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        XMLStreamWriter writer = XOF.createXMLStreamWriter(baos);
        DOMUtil.UTIL.writeNode(r, writer);
        writer.flush();
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        XMLStreamReader reader = XIF.createXMLStreamReader(bais);
        if(log) {
            logger.log(Level.FINE, "Payload = " + baos.toString());
        }
        setPayLoad(reader);
    }
    
    // Methods for debugging purposes.
    
    public static String toString(SOAPMessage soapMessage) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            soapMessage.writeTo(baos);
            return baos.toString();
        } catch(Exception e) {
            return e.getMessage();
        }
    }
    
    
    public static String toString(Node n) {
        return toString(new DOMSource(n));
    }
    
    public static String toString(XMLStreamReader reader) {
        return toString(new StAXSource(reader, true));
    }
    
    public static String toString(Source s) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            StreamResult sr = new StreamResult(baos);
            TF.newTransformer().transform(s, sr);
            return baos.toString();
        } catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
    
    public StreamSource getStreamSource(Source src) {
        try {
            if(src instanceof StreamSource) {
                return (StreamSource)src;
            }
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            StreamResult result = new StreamResult(baos);
            TF.newTransformer().transform(src, result);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            StreamSource ss = new StreamSource(bais);
            return ss;
        } catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
        
    }
    
    public void printPayLoad(String message) {
        if(!log) {
            return;
        }
        StringBuffer msg = new StringBuffer("\n\n");
        if(payLoadAsSource instanceof DOMSource) {
            Node n = ((DOMSource)payLoadAsSource).getNode();
            msg.append("Unwrapped message " + UnWrappedMessage.toString(n));
        }
        msg
                .append(message)
                .append("\n\npayLoadLocalName = ")
                .append(payloadLocalName)
                .append("\npayLoadNamespaceURI = ")
                .append(payloadNamespaceURI)
                .append("\n\n");
        
        logger.log(Level.FINE, msg.toString());
    }
    
    /**
     * Adds the header node to the header list.
     */
    private void addHeader(Node n) {
        if(log) {
            logger.log(Level.FINE, "Header = " + toString(n));
        }
        DOMHeader header = new DOMHeader((Element)n);
        headers.add(header);
    }
    
    /**
     * Adds the header node pointed by XMLStreamReader to the header list.
     */
    private void addHeader(XMLStreamReader r) {
        try {
            if(log) {
                logger.log(Level.FINE, "Header = " + r.getName());
            }
            StreamHeader11 header = new StreamHeader11(r);
            headers.add(header);
        } catch(Exception ex) {
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        }
    }
    
    private void processAttachments() {
        for(String aName : (Set<String>)normalizedMessage.getAttachmentNames()) {
            logger.log(Level.FINE, "Adding attachment with ID = " + aName);
            getAttachments().add(new DataHandlerAttachment(
                    aName, normalizedMessage.getAttachment(aName)));
        }
    }
    
    
// END :: Methods for debugging purposes.
    
    class DocumentStyleUnWrapper {
        
        void unwrap() throws Exception {
            if(nmContent instanceof DOMSource) { // most cases it will be DOMSource
                Node n = ((DOMSource)nmContent).getNode();
                unwrap(getOwnerDocument(n));
            } else if(nmContent instanceof StreamSource) {
                XMLStreamReader reader = XIF.
                        createXMLStreamReader(((StreamSource)nmContent).getInputStream());
                unwrap(reader);
            } else if(nmContent instanceof SAXSource) {
                InputSource source = ((SAXSource) nmContent).getInputSource();
                XMLStreamReader reader = (source.getCharacterStream() != null)?
                                XIF.createXMLStreamReader(source.getCharacterStream()):
                                XIF.createXMLStreamReader(source.getByteStream());
                unwrap(reader);
            } else {
                logger.log(Level.WARNING, "UnWrappedMessage :: Transforming the input message to DOM");
                Transformer t = TF.newTransformer();
                DOMResult result = new DOMResult();
                t.transform(nmContent, result);
                unwrap(getOwnerDocument(result.getNode()));
            }
        }
        
        /**
         * Searches for the payLoad node in the given node and makes
         * payLoadAsSource and payLoadAsStreamReader point to the 'payload' node.
         *
         * If the payLode node is not found in the given node, then payLoadAsSource
         * and payLoadAsStreamReader will remain null.
         *
         * @param n node representing a JBI inbound request message
         * @param operation operation to be invoked on the endpoint
         */
        private void unwrap(Node n) {
            try {
                if(n.getNodeType() == Node.DOCUMENT_NODE) {
                    n = n.getFirstChild();
                }
                if(isJBINode(n, WRAPPER_MESSAGE_LOCALNAME)) {
                    NodeList nl = n.getChildNodes();
                    for(int i=0, partIndex=0; i<wsdlPartBindings.length; i++, partIndex++) {
                        Node partValue = nl.item(partIndex).getFirstChild();
                        switch (wsdlPartBindings[i]) {
                            case SOAP_BODY_BINDING :
                                if(log) {
                                    logger.log(Level.FINE, "Setting part number " + i + " as payload");
                                }
                                setPayLoad(partValue);
                                break;
                            case SOAP_HEADER_BINDING :
                                if(log) {
                                    logger.log(Level.FINE, "Adding part number " + i + " to header");
                                }
                                addHeader(partValue);
                                break;
                            case SOAP_ATTACHMENT_BINDING :
                                if(log) {
                                    logger.log(Level.FINE, "Part number " + i + " is an attachment");
                                }
                                --partIndex; // Stay on the same node.
                                break;
                        }
                    }
                } else {
                    logger.log(Level.SEVERE, "Received message is not <jbi:message>");
                }
            } catch(Exception ex) {
                logger.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
        
        /**
         * Searches for the payLoad in the given reader and makes
         * payLoadAsSource and payLoadAsStreamReader point to the 'payload' node.
         *
         * If the payLode is not found in the given reader, then payLoadAsSource
         * and payLoadAsStreamReader will remain null.
         *
         * @param reader reader pointing to a JBI inbound request message
         * @param operation operation to be invoked on the endpoint
         */
        private void unwrap(XMLStreamReader reader) {
            String methodSig = "UnWrappedMessage$DocumentStyleUnwrapper :: " +
                    "unwrap(XMLStreamReader, QName) : ";
            try {
                if(!findJBINode(reader,WRAPPER_MESSAGE_LOCALNAME)) {
                    logger.log(Level.SEVERE, "Received message is not <jbi:message>");
                    return;
                }
                for(int i=0; i<wsdlPartBindings.length; i++) {
                    switch (wsdlPartBindings[i]) {
                        case SOAP_BODY_BINDING :
                            
                            if(!findJBINode(reader, WRAPPER_PART_LOCALNAME)) {
                                logger.log(Level.SEVERE, "Required <jbi:part> is not found in the received message");
                                continue;
                            }
                            reader.next(); // point reader to <jbi:part>'s value
                            
                            if(wsdlPartBindings.length == 1) {
                                if(log) {
                                    logger.log(Level.FINE, "Setting part number " + i + " as payload");
                                }
                                setPayLoad(reader);
                            } else {
                                if(log) {
                                    logger.log(Level.FINE, "Copying part number " + i + " to payload");
                                }
                                copyPayLoad(reader);
                            }
                            break;
                        case SOAP_HEADER_BINDING :
                            if(!findJBINode(reader, WRAPPER_PART_LOCALNAME)) {
                                logger.log(Level.SEVERE, "Required <jbi:part> is not found in the received message");
                                continue;
                            }
                            reader.next(); // point reader to <jbi:part>'s value
                            
                            if(log) {
                                logger.log(Level.FINE, "Adding part number " + i + " to header");
                            }
                            addHeader(reader);
                            break;
                        case SOAP_ATTACHMENT_BINDING :
                            if(log) {
                                logger.log(Level.FINE, "Part number " + i + " is an attachment");
                            }
                            break;
                    }
                }
            } catch(Exception ex) {
                logger.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
    }
    
    class RPCStyleUnWrapper {
        
        void unwrap() throws Exception {
            if(nmContent instanceof DOMSource) { // most cases it will be DOMSource
                Node n = ((DOMSource)nmContent).getNode();
                unwrap(getOwnerDocument(n));
            } else if(nmContent instanceof StreamSource) {
                XMLStreamReader reader = XIF.
                        createXMLStreamReader(((StreamSource)nmContent).getInputStream());
                unwrap(reader);
            } else if(nmContent instanceof SAXSource) {
                InputSource source = ((SAXSource) nmContent).getInputSource();
                XMLStreamReader reader = (source.getCharacterStream() != null)?
                                XIF.createXMLStreamReader(source.getCharacterStream()):
                                XIF.createXMLStreamReader(source.getByteStream());
                unwrap(reader);
            } else {
                logger.log(Level.WARNING, "UnWrappedMessage :: Transforming the input message to DOM");
                Transformer t = TF.newTransformer();
                DOMResult result = new DOMResult();
                t.transform(nmContent, result);
                unwrap(getOwnerDocument(result.getNode()));
            }
        }
        
        /**
         *
         * Unwraps the incoming JBI request message and sets
         * payLoadAsSource and payLoadAsStreamReader to hold the 'payload'.
         *
         * @param wrappedDocument XMLStreamReader or Node representing the JBI
         * request message which is in the following form:
         *
         * <jbi:message
         *          xmlns:msgns="http://example.web.service/Calculator"
         *          name="add"
         *          type="msgns:add"
         *          version="1.0"
         *          xmlns:jbi="http://java.sun.com/xml/ns/jbi/wsdl-11-wrapper">
         * 	<jbi:part><int_1>1</int_1></jbi:part>
         * 	<jbi:part><int_2>2</int_2></jbi:part>
         * </jbi:message>
         * @param payLoadName Name of the operation to be invoked on the endpoint
         * @param payLoadNsUri Target name space URI which is unique for a webservice.
         * @return Sets payLoadAsSource and payLoadAsStreamReader to the payload which is
         *
         * <ns2:add xmlns:ns2="http://example.web.service/Calculator">
         *      <int_1>1</int_1>
         *      <int_2>2</int_2>
         * </ns2:add>
         */
        private void unwrap(Object wrappedDocument) {
            String methodSig = "UnWrappedMessage$RPCStyleUnwrapper :: " +
                    "unwrap(Object, String, String, ServiceEngineEndpoint) : ";
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                XMLStreamWriter writer = XOF.createXMLStreamWriter(baos);
                /**
                 * Extract the payLoad content from wrappedDocument and write it
                 * to writer. This does not involve creating or importing a DOM node.
                 */
                writer.writeStartElement(DEFAULT_OPERATION_PREFIX + ":" + wsdlMessageType.getLocalPart());
                writer.writeAttribute(DEFAULT_XML_NS_SCHEME + ":" + DEFAULT_OPERATION_PREFIX,
                        wsdlMessageType.getNamespaceURI());
                if(wrappedDocument instanceof Node) {
                    writeJBIParts((Node)wrappedDocument, writer);
                } else if(wrappedDocument instanceof XMLStreamReader) {
                    writeJBIParts((XMLStreamReader)wrappedDocument, writer);
                }
                writer.writeEndElement();
                writer.flush();
                /**
                 * Create payLoadAsStreamReader and payLoadAsSource from the
                 * content available in ByteArrayOutputStream.
                 */
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                payLoadAsBaos = baos;
                payloadLocalName = wsdlMessageType.getLocalPart();
                payloadNamespaceURI = wsdlMessageType.getNamespaceURI();
                payLoadAsStreamReader = XIF.createXMLStreamReader(bais);
                payLoadAsStreamReader.next(); // skip the <?xml ...?> node.
                payLoadAsSource = new StAXSource(payLoadAsStreamReader, true);
                
                printPayLoad("Unwrapped message = " + baos.toString());
            } catch(Exception ex) {
                logger.log(Level.SEVERE, ex.getMessage(), ex);
            }
        }
        
        private boolean isSimpleType(Part part) {
            QName parttype = part.getTypeName();
            if (parttype != null) {
                String s = parttype.getNamespaceURI();
                if ( s != null && s.trim().equals("http://www.w3.org/2001/XMLSchema")) {
                    return true;
                }
            }
            return false;
        }
        
        private void writeJBIParts(XMLStreamReader reader,
                XMLStreamWriter writer) throws Exception {
            long startTime = System.currentTimeMillis();
            /**
             * The following loop is expected to iterate only once always,
             * because there could be only one <jbi:message> in the request.
             */
            
            if(!findJBINode(reader, WRAPPER_MESSAGE_LOCALNAME)) {
                logger.log(Level.SEVERE, "Received message is not <jbi:message>");
                return;
            }
            
            for(int k=0; k<wsdlPartBindings.length; k++) {
                switch(wsdlPartBindings[k]) {
                    case SOAP_HEADER_BINDING :
                        if(!findJBINode(reader, WRAPPER_PART_LOCALNAME)) {
                            logger.log(Level.SEVERE, "Required <jbi:part> is not found in the received message");
                            continue;
                        }
                        /**
                         * <jbi:part>'s value will always be an element, so
                         * point reader to <jbi:part>'s value.
                         */
                        reader.next();
                        if(log) {
                            logger.log(Level.FINE, "Adding part number " + k + " to header");
                        }
                        addHeader(reader);
                        break;
                    case SOAP_BODY_BINDING :
                        if(!findJBINode(reader, WRAPPER_PART_LOCALNAME)) {
                            logger.log(Level.SEVERE, "Required <jbi:part> is not found in the received message");
                            continue;
                        }
                        if(log) {
                            logger.log(Level.FINE, "Adding part number " + k + " to payload");
                        }
                        Part part = wsdlOrderedParts.get(k);
                        writer.writeStartElement(part.getName());
                        DOMUtil.UTIL.writeChildren(reader, writer);
                        writer.writeEndElement();
                        break;
                    case SOAP_ATTACHMENT_BINDING :
                        if(log) {
                            logger.log(Level.FINE, "Part number " + k + " is an attachment");
                        }
                        break;
                }
            }
            
            long timeTaken = System.currentTimeMillis() - startTime;
            if(log) {
                logger.log(Level.FINE, "TimeTaken to write JBI parts to payload = " + timeTaken);
            }
        }
        
        private void writeJBIParts(Node wrappedDocument,
                XMLStreamWriter writer) throws Exception {
            NodeList jbiMessages = wrappedDocument.getChildNodes();
            /**
             * The following loop is expected to iterate only once always,
             * because there could be only one <jbi:message> in the request.
             */
            long startTime = System.currentTimeMillis();
            for(int i=0; i<jbiMessages.getLength(); i++) {
                Node jbiMessage = jbiMessages.item(i);
                if(!isJBINode(jbiMessage, WRAPPER_MESSAGE_LOCALNAME)) continue;
                NodeList jbiParts = jbiMessage.getChildNodes();
                /**
                 * The following loop is expected to iterate as much as
                 * there are <jbi:part> elements.
                 */
                for(int j = 0, k = 0; j< jbiParts.getLength(); j++) {
                    Node jbiPart = jbiParts.item(j);
                    if(!isJBINode(jbiPart, WRAPPER_PART_LOCALNAME)) continue;
                    
                    switch(wsdlPartBindings[k]) {
                        
                        case SOAP_HEADER_BINDING :
                            /**
                             * <jbi:part>'s value will always be an element, so
                             * add <jbi:part>'s value as header.
                             */
                            if(log) {
                                logger.log(Level.FINE, "Adding part number " + k + " as header");
                            }
                            addHeader(jbiPart.getFirstChild());
                            break;
                            
                        case SOAP_BODY_BINDING :
                            if(log) {
                                logger.log(Level.FINE, "Adding part number " + k + " to payload");
                            }
                            Part part = wsdlOrderedParts.get(k);
                            writer.writeStartElement(part.getName());
                            DOMUtil.UTIL.writeChildren(writer, jbiPart);
                            writer.writeEndElement();
                            break;
                        case SOAP_ATTACHMENT_BINDING :
                            if(log) {
                                logger.log(Level.FINE, "Part number " + k + " is an attachment");
                            }
                            --j; // stay on the same node.
                            break;
                    }
                    ++k;
                }
            }
            long timeTaken = System.currentTimeMillis() - startTime;
            if(log) {
                logger.log(Level.FINE, "TimeTaken to write JBI parts to payload = " + timeTaken);
            }
        }
        
    }
    
    private boolean findJBINode(XMLStreamReader reader, String localName) throws Exception {
        while(reader.hasNext()) {
            if(isJBINode(reader,localName)) {
                return true;
            }
            reader.next();
        }
        return false;
    }
    
    private boolean isJBINode(Node node, String localName) {
        if(WRAPPER_DEFAULT_NAMESPACE.equalsIgnoreCase(node.getNamespaceURI()) &&
                localName.equalsIgnoreCase(node.getLocalName())) {
            return true;
        }
        return false;
    }
    
    private boolean isJBINode(XMLStreamReader reader, String localName) {
        if(reader.getEventType() != XMLStreamReader.START_ELEMENT) {
            return false;
        }
        if(WRAPPER_DEFAULT_NAMESPACE.equalsIgnoreCase(reader.getNamespaceURI()) &&
                localName.equalsIgnoreCase(reader.getLocalName())) {
            return true;
        }
        return false;
    }
    
    public Node getOwnerDocument(Node n) {
        Node ownerDocument = n.getOwnerDocument();
        return ownerDocument != null
                ? ownerDocument
                : n;
    }
    
    private void unWrapFault() throws Exception {
        Source s = this.nmContent;
        Node n;
        if(s instanceof DOMSource) {
            n = ((DOMSource)s).getNode();
        } else {
            Transformer t = TF.newTransformer();
            DOMResult result = new DOMResult();
            t.transform(s, result);
            n = result.getNode();
        }
        
        Document d = (n instanceof Document) ? (Document) n : n.getOwnerDocument();
        
        NodeList nl = d.getElementsByTagNameNS(WRAPPER_DEFAULT_NAMESPACE, WRAPPER_PART_LOCALNAME);
        Node jbiPart = (nl != null && nl.getLength() > 0)
        ? nl.item(0).getFirstChild()
        : d.getFirstChild();
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        XMLStreamWriter writer = XOF.createXMLStreamWriter(baos);
        
        writer.writeStartDocument();
        writer.writeStartElement(SOAP_FAULT);
        writer.writeAttribute("xmlns:" + SOAP_PREFIX, SOAP_NAMESPACE);
        
        String faultCode = jbiPart == null ? SERVER_FAULT_CODE : CLIENT_FAULT_CODE;
        String faultString = FAULT_STRING;
        
        writer.writeStartElement(FAULT_CODE_ELEMENT);
        writer.writeCharacters(SOAP_PREFIX + ":" + faultCode);
        writer.writeEndElement();
        
        writer.writeStartElement(FAULT_STRING_ELEMENT);
        writer.writeCharacters(faultString);
        writer.writeEndElement();
        
        writer.writeStartElement(FAULT_DETAIL_ELEMENT);
        if(jbiPart != null)
            DOMUtil.UTIL.writeNode(jbiPart, writer);
        
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndDocument();
        writer.flush();
        
        setPayLoad(baos.toByteArray());
        
        printPayLoad("\n\nUnwrapped fault = " + baos.toString());
    }
    
    public void setPayLoad(byte[] data) throws Exception {
        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        payLoadAsStreamReader = XIF.createXMLStreamReader(bais);
        payLoadAsStreamReader.next(); // skip the <?xml ...?> node.
        payLoadAsSource = new StAXSource(payLoadAsStreamReader, true);
        payloadLocalName = payLoadAsStreamReader.getLocalName();
        payloadNamespaceURI = payLoadAsStreamReader.getNamespaceURI();
    }
    
}