src/share/jaxws_classes/com/sun/xml/internal/ws/api/message/Messages.java

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

     1 /*
     2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.ws.api.message;
    28 import com.sun.istack.internal.NotNull;
    29 import com.sun.istack.internal.Nullable;
    30 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
    31 import com.sun.xml.internal.ws.api.SOAPVersion;
    32 import com.sun.xml.internal.ws.api.WSBinding;
    33 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
    34 import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
    35 import com.sun.xml.internal.ws.api.pipe.Tube;
    36 import com.sun.xml.internal.ws.api.pipe.Codecs;
    37 import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
    38 import com.sun.xml.internal.ws.message.AttachmentSetImpl;
    39 import com.sun.xml.internal.ws.message.DOMMessage;
    40 import com.sun.xml.internal.ws.message.EmptyMessageImpl;
    41 import com.sun.xml.internal.ws.message.ProblemActionHeader;
    42 import com.sun.xml.internal.ws.message.stream.PayloadStreamReaderMessage;
    43 import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
    44 import com.sun.xml.internal.ws.message.source.PayloadSourceMessage;
    45 import com.sun.xml.internal.ws.message.source.ProtocolSourceMessage;
    46 import com.sun.xml.internal.ws.spi.db.BindingContextFactory;
    47 import com.sun.xml.internal.ws.streaming.XMLStreamReaderException;
    48 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
    49 import com.sun.xml.internal.ws.util.DOMUtil;
    50 import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
    51 import com.sun.xml.internal.ws.addressing.model.MissingAddressingHeaderException;
    52 import com.sun.xml.internal.ws.resources.AddressingMessages;
    53 import org.w3c.dom.Element;
    54 import org.w3c.dom.Node;
    56 import javax.xml.bind.JAXBContext;
    57 import javax.xml.bind.JAXBElement;
    58 import javax.xml.bind.Marshaller;
    59 import javax.xml.bind.annotation.XmlRootElement;
    60 import javax.xml.namespace.QName;
    61 import javax.xml.soap.*;
    62 import javax.xml.stream.XMLStreamConstants;
    63 import javax.xml.stream.XMLStreamException;
    64 import javax.xml.stream.XMLStreamReader;
    65 import javax.xml.transform.Source;
    66 import javax.xml.transform.sax.SAXSource;
    67 import javax.xml.transform.stream.StreamSource;
    68 import javax.xml.transform.dom.DOMSource;
    69 import javax.xml.ws.ProtocolException;
    70 import javax.xml.ws.WebServiceException;
    72 /**
    73  * Factory methods for various {@link Message} implementations.
    74  *
    75  * <p>
    76  * This class provides various methods to create different
    77  * flavors of {@link Message} classes that store data
    78  * in different formats.
    79  *
    80  * <p>
    81  * This is a part of the JAX-WS RI internal API so that
    82  * {@link Tube} implementations can reuse the implementations
    83  * done inside the JAX-WS.
    84  *
    85  * <p>
    86  * If you find some of the useful convenience methods missing
    87  * from this class, please talk to us.
    88  *
    89  *
    90  * @author Kohsuke Kawaguchi
    91  */
    92 public abstract class Messages {
    93     private Messages() {}
    95     /**
    96      * Creates a {@link Message} backed by a JAXB bean.
    97      * @deprecated
    98      * @param context
    99      *      The context to be used to produce infoset from the object. Must not be null.
   100      * @param jaxbObject
   101      *      The JAXB object that represents the payload. must not be null. This object
   102      *      must be bound to an element (which means it either is a {@link JAXBElement} or
   103      *      an instanceof a class with {@link XmlRootElement}).
   104      * @param soapVersion
   105      *      The SOAP version of the message. Must not be null.
   106      */
   107     public static Message create(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
   108         return JAXBMessage.create(context,jaxbObject,soapVersion);
   109     }
   111     /**
   112      * @deprecated
   113      * For use when creating a Dispatch object with an unknown JAXB implementation
   114      * for he JAXBContext parameter.
   115      *
   116      */
   117     public static Message createRaw(JAXBContext context, Object jaxbObject, SOAPVersion soapVersion) {
   118         return JAXBMessage.createRaw(context,jaxbObject,soapVersion);
   119     }
   121     /**
   122      * @deprecated
   123      *      Use {@link #create(JAXBRIContext, Object, SOAPVersion)}
   124      */
   125     public static Message create(Marshaller marshaller, Object jaxbObject, SOAPVersion soapVersion) {
   126         return create(BindingContextFactory.getBindingContext(marshaller).getJAXBContext(),jaxbObject,soapVersion);
   127     }
   129     /**
   130      * Creates a {@link Message} backed by a SAAJ {@link SOAPMessage} object.
   131      *
   132      * <p>
   133      * If the {@link SOAPMessage} contains headers and attachments, this method
   134      * does the right thing.
   135      *
   136      * @param saaj
   137      *      The SOAP message to be represented as a {@link Message}.
   138      *      Must not be null. Once this method is invoked, the created
   139      *      {@link Message} will own the {@link SOAPMessage}, so it shall
   140      *      never be touched directly.
   141      */
   142     public static Message create(SOAPMessage saaj) {
   143         return SAAJFactory.create(saaj);
   144     }
   146     /**
   147      * Creates a {@link Message} using {@link Source} as payload.
   148      *
   149      * @param payload
   150      *      Source payload is {@link Message}'s payload
   151      *      Must not be null. Once this method is invoked, the created
   152      *      {@link Message} will own the {@link Source}, so it shall
   153      *      never be touched directly.
   154      *
   155      * @param ver
   156      *      The SOAP version of the message. Must not be null.
   157      */
   158     public static Message createUsingPayload(Source payload, SOAPVersion ver) {
   159         if (payload instanceof DOMSource) {
   160             if (((DOMSource)payload).getNode() == null) {
   161                 return new EmptyMessageImpl(ver);
   162             }
   163         } else if (payload instanceof StreamSource) {
   164             StreamSource ss = (StreamSource)payload;
   165             if (ss.getInputStream() == null && ss.getReader() == null && ss.getSystemId() == null) {
   166                 return new EmptyMessageImpl(ver);
   167             }
   168         } else if (payload instanceof SAXSource) {
   169             SAXSource ss = (SAXSource)payload;
   170             if (ss.getInputSource() == null && ss.getXMLReader() == null) {
   171                 return new EmptyMessageImpl(ver);
   172             }
   173         }
   174         return new PayloadSourceMessage(payload, ver);
   175     }
   177     /**
   178      * Creates a {@link Message} using {@link XMLStreamReader} as payload.
   179      *
   180      * @param payload
   181      *      XMLStreamReader payload is {@link Message}'s payload
   182      *      Must not be null. Once this method is invoked, the created
   183      *      {@link Message} will own the {@link XMLStreamReader}, so it shall
   184      *      never be touched directly.
   185      *
   186      * @param ver
   187      *      The SOAP version of the message. Must not be null.
   188      */
   189     public static Message createUsingPayload(XMLStreamReader payload, SOAPVersion ver) {
   190         return new PayloadStreamReaderMessage(payload, ver);
   191     }
   193     /**
   194      * Creates a {@link Message} from an {@link Element} that represents
   195      * a payload.
   196      *
   197      * @param payload
   198      *      The element that becomes the child element of the SOAP body.
   199      *      Must not be null.
   200      *
   201      * @param ver
   202      *      The SOAP version of the message. Must not be null.
   203      */
   204     public static Message createUsingPayload(Element payload, SOAPVersion ver) {
   205         return new DOMMessage(ver,payload);
   206     }
   208     /**
   209      * Creates a {@link Message} from an {@link Element} that represents
   210      * the whole SOAP message.
   211      *
   212      * @param soapEnvelope
   213      *      The SOAP envelope element.
   214      */
   215     public static Message create(Element soapEnvelope) {
   216         SOAPVersion ver = SOAPVersion.fromNsUri(soapEnvelope.getNamespaceURI());
   217         // find the headers
   218         Element header = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Header");
   219         HeaderList headers = null;
   220         if(header!=null) {
   221             for( Node n=header.getFirstChild(); n!=null; n=n.getNextSibling() ) {
   222                 if(n.getNodeType()==Node.ELEMENT_NODE) {
   223                     if(headers==null)
   224                         headers = new HeaderList(ver);
   225                     headers.add(Headers.create((Element)n));
   226                 }
   227             }
   228         }
   230         // find the payload
   231         Element body = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
   232         if(body==null)
   233             throw new WebServiceException("Message doesn't have <S:Body> "+soapEnvelope);
   234         Element payload = DOMUtil.getFirstChild(soapEnvelope, ver.nsUri, "Body");
   236         if(payload==null) {
   237             return new EmptyMessageImpl(headers, new AttachmentSetImpl(), ver);
   238         } else {
   239             return new DOMMessage(ver,headers,payload);
   240         }
   241     }
   243     /**
   244      * Creates a {@link Message} using Source as entire envelope.
   245      *
   246      * @param envelope
   247      *      Source envelope is used to create {@link Message}
   248      *      Must not be null. Once this method is invoked, the created
   249      *      {@link Message} will own the {@link Source}, so it shall
   250      *      never be touched directly.
   251      *
   252      */
   253     public static Message create(Source envelope, SOAPVersion soapVersion) {
   254         return new ProtocolSourceMessage(envelope, soapVersion);
   255     }
   258     /**
   259      * Creates a {@link Message} that doesn't have any payload.
   260      */
   261     public static Message createEmpty(SOAPVersion soapVersion) {
   262         return new EmptyMessageImpl(soapVersion);
   263     }
   265     /**
   266      * Creates a {@link Message} from {@link XMLStreamReader} that points to
   267      * the start of the envelope.
   268      *
   269      * @param reader
   270      *      can point to the start document or the start element (of &lt;s:Envelope>)
   271      */
   272     public static @NotNull Message create(@NotNull XMLStreamReader reader) {
   273         // skip until the root element
   274         if(reader.getEventType()!=XMLStreamConstants.START_ELEMENT)
   275             XMLStreamReaderUtil.nextElementContent(reader);
   276         assert reader.getEventType()== XMLStreamConstants.START_ELEMENT :reader.getEventType();
   278         SOAPVersion ver = SOAPVersion.fromNsUri(reader.getNamespaceURI());
   280         return Codecs.createSOAPEnvelopeXmlCodec(ver).decode(reader);
   281     }
   283     /**
   284      * Creates a {@link Message} from {@link XMLStreamBuffer} that retains the
   285      * whole envelope infoset.
   286      *
   287      * @param xsb
   288      *      This buffer must contain the infoset of the whole envelope.
   289      */
   290     public static @NotNull Message create(@NotNull XMLStreamBuffer xsb) {
   291         // TODO: we should be able to let Messae know that it's working off from a buffer,
   292         // to make some of the operations more efficient.
   293         // meanwhile, adding this as an API so that our users can take advantage of it
   294         // when we get around to such an implementation later.
   295         try {
   296             return create(xsb.readAsXMLStreamReader());
   297         } catch (XMLStreamException e) {
   298             throw new XMLStreamReaderException(e);
   299         }
   300     }
   302     /**
   303      * Creates a {@link Message} that represents an exception as a fault. The
   304      * created message reflects if t or t.getCause() is SOAPFaultException.
   305      *
   306      * creates a fault message with default faultCode env:Server if t or t.getCause()
   307      * is not SOAPFaultException. Otherwise, it use SOAPFaultException's faultCode
   308      *
   309      * @return
   310      *      Always non-null. A message that wraps this {@link Throwable}.
   311      *
   312      */
   313     public static Message create(Throwable t, SOAPVersion soapVersion) {
   314         return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, null, t);
   315     }
   317     /**
   318      * Creates a fault {@link Message}.
   319      *
   320      * <p>
   321      * This method is not designed for efficiency, and we don't expect
   322      * to be used for the performance critical codepath.
   323      *
   324      * @param fault
   325      *      The populated SAAJ data structure that represents a fault
   326      *      in detail.
   327      *
   328      * @return
   329      *      Always non-null. A message that wraps this {@link SOAPFault}.
   330      */
   331     public static Message create(SOAPFault fault) {
   332         SOAPVersion ver = SOAPVersion.fromNsUri(fault.getNamespaceURI());
   333         return new DOMMessage(ver,fault);
   334     }
   336     /**
   337      * @deprecated
   338      *      Use {@link #createAddressingFaultMessage(WSBinding, Packet, QName)}
   339      */
   340     public static Message createAddressingFaultMessage(WSBinding binding, QName missingHeader) {
   341         return createAddressingFaultMessage(binding,null,missingHeader);
   342     }
   344     /**
   345      * Creates a fault {@link Message} that captures the code/subcode/subsubcode
   346      * defined by WS-Addressing if one of the expected WS-Addressing headers is
   347      * missing in the message
   348      *
   349      * @param binding WSBinding
   350      * @param p
   351      *      {@link Packet} that was missing a WS-Addressing header.
   352      * @param missingHeader The missing WS-Addressing Header
   353      * @return
   354      *      A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
   355      */
   356     public static Message createAddressingFaultMessage(WSBinding binding, Packet p, QName missingHeader) {
   357         AddressingVersion av = binding.getAddressingVersion();
   358         if(av == null) {
   359             // Addressing is not enabled.
   360             throw new WebServiceException(AddressingMessages.ADDRESSING_SHOULD_BE_ENABLED());
   361         }
   362         WsaTubeHelper helper = av.getWsaHelper(null,null,binding);
   363         return create(helper.newMapRequiredFault(new MissingAddressingHeaderException(missingHeader,p)));
   364     }
   365     /**
   366      * Creates a fault {@link Message} that captures the code/subcode/subsubcode
   367      * defined by WS-Addressing if wsa:Action is not supported.
   368      *
   369      * @param unsupportedAction The unsupported Action. Must not be null.
   370      * @param av The WS-Addressing version of the message. Must not be null.
   371      * @param sv The SOAP Version of the message. Must not be null.
   372      *
   373      * @return
   374      *      A message representing SOAPFault that contains the WS-Addressing code/subcode/subsubcode.
   375      */
   376     public static Message create(@NotNull String unsupportedAction, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   377         QName subcode = av.actionNotSupportedTag;
   378         String faultstring = String.format(av.actionNotSupportedText, unsupportedAction);
   380         Message faultMessage;
   381         SOAPFault fault;
   382         try {
   383             if (sv == SOAPVersion.SOAP_12) {
   384                 fault = SOAPVersion.SOAP_12.getSOAPFactory().createFault();
   385                 fault.setFaultCode(SOAPConstants.SOAP_SENDER_FAULT);
   386                 fault.appendFaultSubcode(subcode);
   387                 Detail detail = fault.addDetail();
   388                 SOAPElement se = detail.addChildElement(av.problemActionTag);
   389                 se = se.addChildElement(av.actionTag);
   390                 se.addTextNode(unsupportedAction);
   391             } else {
   392                 fault = SOAPVersion.SOAP_11.getSOAPFactory().createFault();
   393                 fault.setFaultCode(subcode);
   394             }
   395             fault.setFaultString(faultstring);
   397             faultMessage = SOAPFaultBuilder.createSOAPFaultMessage(sv, fault);
   398             if (sv == SOAPVersion.SOAP_11) {
   399                 faultMessage.getHeaders().add(new ProblemActionHeader(unsupportedAction, av));
   400             }
   401         } catch (SOAPException e) {
   402             throw new WebServiceException(e);
   403         }
   405         return faultMessage;
   406     }
   408     /**
   409      * To be called to convert a  {@link ProtocolException} and faultcode for a given {@link SOAPVersion} in to a {@link Message}.
   410      *
   411      * @param soapVersion {@link SOAPVersion#SOAP_11} or {@link SOAPVersion#SOAP_12}
   412      * @param pex a ProtocolException
   413      * @param faultcode soap faultcode. Its ignored if the {@link ProtocolException} instance is {@link javax.xml.ws.soap.SOAPFaultException} and it has a
   414      * faultcode present in the underlying {@link SOAPFault}.
   415      * @return {@link Message} representing SOAP fault
   416      */
   417     public static @NotNull Message create(@NotNull SOAPVersion soapVersion, @NotNull ProtocolException pex, @Nullable QName faultcode){
   418         return SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, pex, faultcode);
   419     }
   420 }

mercurial