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  */
  25 
  26 package com.sun.xml.internal.ws.api.message;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.xml.internal.bind.api.Bridge;
  31 import com.sun.xml.internal.ws.api.BindingID;
  32 import com.sun.xml.internal.ws.api.SOAPVersion;
  33 import com.sun.xml.internal.ws.api.WSBinding;
  34 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
  35 import com.sun.xml.internal.ws.api.model.JavaMethod;
  36 import com.sun.xml.internal.ws.api.model.SEIModel;
  37 import com.sun.xml.internal.ws.api.model.WSDLOperationMapping;
  38 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
  39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundPortType;
  40 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
  41 import com.sun.xml.internal.ws.api.pipe.Codec;
  42 import com.sun.xml.internal.ws.api.pipe.Pipe;
  43 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
  44 import com.sun.xml.internal.ws.client.dispatch.DispatchImpl;
  45 import com.sun.xml.internal.ws.message.AttachmentSetImpl;
  46 import com.sun.xml.internal.ws.message.StringHeader;
  47 import com.sun.xml.internal.ws.message.jaxb.JAXBMessage;
  48 import com.sun.xml.internal.ws.spi.db.XMLBridge;
  49 import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
  50 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
  51 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx;
  52 import org.xml.sax.ContentHandler;
  53 import org.xml.sax.ErrorHandler;
  54 import org.xml.sax.SAXException;
  55 import org.xml.sax.SAXParseException;
  56 
  57 import javax.xml.bind.JAXBException;
  58 import javax.xml.bind.Unmarshaller;
  59 import javax.xml.namespace.QName;
  60 import javax.xml.soap.MimeHeaders;
  61 import javax.xml.soap.SOAPException;
  62 import javax.xml.soap.SOAPMessage;
  63 import javax.xml.stream.XMLStreamException;
  64 import javax.xml.stream.XMLStreamReader;
  65 import javax.xml.stream.XMLStreamWriter;
  66 import javax.xml.transform.Source;
  67 import javax.xml.ws.Dispatch;
  68 import javax.xml.ws.WebServiceException;
  69 import java.io.InputStream;
  70 import java.lang.reflect.Method;
  71 import java.lang.reflect.Proxy;
  72 import java.util.List;
  73 import java.util.Map;
  74 import java.util.UUID;
  75 
  76 /**
  77  * Represents a SOAP message.
  78  *
  79  *
  80  * <h2>What is a message?</h2>
  81  * <p>
  82  * A {@link Message} consists of the following:
  83  *
  84  * <ol>
  85  * <li>
  86  *    Random-accessible list of headers.
  87  *    a header is a representation of an element inside
  88  *    &lt;soap:Header>.
  89  *    It can be read multiple times,
  90  *    can be added or removed, but it is not modifiable.
  91  *    See {@link HeaderList} for more about headers.
  92  *
  93  * <li>
  94  *    The payload of the message, which is a representation
  95  *    of an element inside &lt;soap:Body>.
  96  *    the payload is streamed, and therefore it can be
  97  *    only read once (or can be only written to something once.)
  98  *    once a payload is used, a message is said to be <b>consumed</b>.
  99  *    A message {@link #hasPayload() may not have any payload.}
 100  *
 101  * <li>
 102  *    Attachments.
 103  *    TODO: can attachments be streamed? I suspect so.
 104  *    does anyone need to read attachment twice?
 105  *
 106  * </ol>
 107  *
 108  *
 109  * <h2>How does this abstraction work?</h2>
 110  * <p>
 111  * The basic idea behind the {@link Message} is to hide the actual
 112  * data representation. For example, a {@link Message} might be
 113  * constructed on top of an {@link InputStream} from the accepted HTTP connection,
 114  * or it might be constructed on top of a JAXB object as a result
 115  * of the method invocation through {@link Proxy}. There will be
 116  * a {@link Message} implementation for each of those cases.
 117  *
 118  * <p>
 119  * This interface provides a lot of methods that access the payload
 120  * in many different forms, and implementations can implement those
 121  * methods in the best possible way.
 122  *
 123  * <p>
 124  * A particular attention is paid to make sure that a {@link Message}
 125  * object can be constructed on a stream that is not fully read yet.
 126  * We believe this improves the turn-around time on the server side.
 127  *
 128  * <p>
 129  * It is often useful to wrap a {@link Message} into another {@link Message},
 130  * for example to encrypt the body, or to verify the signature as the body
 131  * is read.
 132  *
 133  * <p>
 134  * This representation is also used for a REST-ful XML message.
 135  * In such case we'll construct a {@link Message} with empty
 136  * attachments and headers, and when serializing all headers
 137  * and attachments will be ignored.
 138  *
 139  *
 140  *
 141  * <h2>Message and XOP</h2>
 142  * <p>
 143  * XOP is considered as an {@link Codec}, and therefore when you are looking at
 144  * {@link Message}, you'll never see &lt;xop:Include> or any such elements
 145  * (instead you'll see the base64 data inlined.) If a consumer of infoset isn't
 146  * interested in handling XOP by himself, this allows him to work with XOP
 147  * correctly even without noticing it.
 148  *
 149  * <p>
 150  * For producers and consumers that are interested in accessing the binary data
 151  * more efficiently, they can use {@link XMLStreamReaderEx} and
 152  * {@link XMLStreamWriterEx}.
 153  *
 154  *
 155  *
 156  * <h2>Message lifespan</h2>
 157  * <p>
 158  * Often {@link Packet} include information local to a particular
 159  * invocaion (such as {@code HttpServletRequest}, from this angle, it makes sense
 160  * to tie a lifespan of a message to one pipeline invocation.
 161  * <p>
 162  * On the other hand, if you think about WS-RM, it often needs to hold on to
 163  * a message longer than a pipeline invocation (you might get an HTTP request,
 164  * get a message X, get a second HTTP request, get another message Y, and
 165  * only then you might want to process X.)
 166  * <p>
 167  * TODO: what do we do about this?
 168  *
 169  *
 170  * <pre>
 171  * TODO: can body element have foreign attributes? maybe ID for security?
 172  *       Yes, when the SOAP body is signed there will be an ID attribute present
 173  *       But in this case any security based impl may need access
 174  *       to the concrete representation.
 175  * TODO: HTTP headers?
 176  *       Yes. Abstracted as transport-based properties.
 177  * TODO: who handles SOAP 1.1 and SOAP 1.2 difference?
 178  *       As separate channel implementations responsible for the creation of the
 179  *       message?
 180  * TODO: session?
 181  * TODO: Do we need to expose SOAPMessage explicitly?
 182  *       SOAPMessage could be the concrete representation but is it necessary to
 183  *       transform between different concrete representations?
 184  *       Perhaps this comes down to how use channels for creation and processing.
 185  * TODO: Do we need to distinguish better between creation and processing?
 186  *       Do we really need the requirement that a created message can be resused
 187  *       for processing. Shall we bifurcate?
 188  *
 189  * TODO: SOAP version issue
 190  *       SOAP version is determined by the context, so message itself doesn't carry it around (?)
 191  *
 192  * TODO: wrapping message needs easier. in particular properties and attachments.
 193  * </pre>
 194  *
 195  * @author Kohsuke Kawaguchi
 196  */
 197 public abstract class Message {
 198 
 199     /**
 200      * Returns true if headers are present in the message.
 201      *
 202      * @return
 203      *      true if headers are present.
 204      */
 205     public abstract boolean hasHeaders();
 206 
 207     /**
 208      * Gets all the headers of this message.
 209      *
 210      * <h3>Implementation Note</h3>
 211      * <p>
 212      * {@link Message} implementation is allowed to defer
 213      * the construction of {@link MessageHeaders} object. So
 214      * if you only want to check for the existence of any header
 215      * element, use {@link #hasHeaders()}.
 216      *
 217      * @return
 218      *      always return the same non-null object.
 219      */
 220     public abstract @NotNull MessageHeaders getHeaders();
 221 
 222     /**
 223      * Gets the attachments of this message
 224      * (attachments live outside a message.)
 225      */
 226     public @NotNull AttachmentSet getAttachments() {
 227         if (attachmentSet == null) {
 228             attachmentSet = new AttachmentSetImpl();
 229         }
 230         return attachmentSet;
 231     }
 232 
 233     /**
 234      * Optimization hint for the derived class to check
 235      * if we may have some attachments.
 236      */
 237     protected boolean hasAttachments() {
 238         return attachmentSet!=null;
 239     }
 240 
 241     protected AttachmentSet attachmentSet;
 242 
 243     private WSDLBoundOperation operation = null;
 244 
 245     private WSDLOperationMapping wsdlOperationMapping = null;
 246 
 247     private MessageMetadata messageMetadata = null;
 248 
 249     public void setMessageMedadata(MessageMetadata metadata) {
 250         messageMetadata = metadata;
 251     }
 252 
 253 
 254     /**
 255      * Returns the operation of which this message is an instance of.
 256      *
 257      * <p>
 258      * This method relies on {@link WSDLBoundPortType#getOperation(String, String)} but
 259      * it does so in an efficient way.
 260      *
 261      * @deprecated  It is not always possible to uniquely identify the WSDL Operation from just the
 262      * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
 263      * to get it correctly.
 264      *
 265      * <p>
 266      * This method works only for a request. A pipe can determine an operation for a request,
 267      * and then keep it in a local variable to use it with a response, so there should be
 268      * no need to find out operation from a response (besides, there might not be any response!).
 269      *
 270      * @param boundPortType
 271      *      This represents the port for which this message is used.
 272      *      Most {@link Pipe}s should get this information when they are created,
 273      *      since a pippeline always work against a particular type of {@link WSDLPort}.
 274      *
 275      * @return
 276      *      Null if the operation was not found. This is possible, for example when a protocol
 277      *      message is sent through a pipeline, or when we receive an invalid request on the server,
 278      *      or when we are on the client and the user appliation sends a random DOM through
 279      *      {@link Dispatch}, so this error needs to be handled gracefully.
 280      */
 281     @Deprecated
 282     public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLBoundPortType boundPortType) {
 283         if (operation == null && messageMetadata != null) {
 284             if (wsdlOperationMapping == null) wsdlOperationMapping = messageMetadata.getWSDLOperationMapping();
 285             if (wsdlOperationMapping != null) operation = wsdlOperationMapping.getWSDLBoundOperation();
 286         }
 287         if(operation==null)
 288             operation = boundPortType.getOperation(getPayloadNamespaceURI(),getPayloadLocalPart());
 289         return operation;
 290     }
 291 
 292     /**
 293      * The same as {@link #getOperation(WSDLBoundPortType)} but
 294      * takes {@link WSDLPort} for convenience.
 295      *
 296      * @deprecated  It is not always possible to uniquely identify the WSDL Operation from just the
 297      * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
 298      * to get it correctly.
 299      */
 300     @Deprecated
 301     public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLPort port) {
 302         return getOperation(port.getBinding());
 303     }
 304 
 305     /**
 306      * Returns the java Method of which this message is an instance of.
 307      *
 308      * It is not always possible to uniquely identify the WSDL Operation from just the
 309      * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()}
 310      * to get the QName of the associated wsdl operation correctly.
 311      *
 312      * <p>
 313      * This method works only for a request. A pipe can determine a {@link Method}
 314      * for a request, and then keep it in a local variable to use it with a response,
 315      * so there should be no need to find out operation from a response (besides,
 316      * there might not be any response!).
 317      *
 318      * @param seiModel
 319      *      This represents the java model for the endpoint
 320      *      Some server {@link Pipe}s would get this information when they are created.
 321      *
 322      * @return
 323      *      Null if there is no corresponding Method for this message. This is
 324      *      possible, for example when a protocol message is sent through a
 325      *      pipeline, or when we receive an invalid request on the server,
 326      *      or when we are on the client and the user appliation sends a random
 327      *      DOM through {@link Dispatch}, so this error needs to be handled
 328      *      gracefully.
 329      */
 330     @Deprecated
 331     public final @Nullable JavaMethod getMethod(@NotNull SEIModel seiModel) {
 332         if (wsdlOperationMapping == null && messageMetadata != null) {
 333             wsdlOperationMapping = messageMetadata.getWSDLOperationMapping();
 334         }
 335         if (wsdlOperationMapping != null) {
 336             return wsdlOperationMapping.getJavaMethod();
 337         }
 338         //fall back to the original logic which could be incorrect ...
 339         String localPart = getPayloadLocalPart();
 340         String nsUri;
 341         if (localPart == null) {
 342             localPart = "";
 343             nsUri = "";
 344         } else {
 345             nsUri = getPayloadNamespaceURI();
 346         }
 347         QName name = new QName(nsUri, localPart);
 348         return seiModel.getJavaMethod(name);
 349     }
 350 
 351     private Boolean isOneWay;
 352 
 353     /**
 354      * Returns true if this message is a request message for a
 355      * one way operation according to the given WSDL. False otherwise.
 356      *
 357      * <p>
 358      * This method is functionally equivalent as doing
 359      * {@code getOperation(port).getOperation().isOneWay()}
 360      * (with proper null check and all.) But this method
 361      * can sometimes work faster than that (for example,
 362      * on the client side when used with SEI.)
 363      *
 364      * @param port
 365      *      {@link Message}s are always created under the context of
 366      *      one {@link WSDLPort} and they never go outside that context.
 367      *      Pass in that "governing" {@link WSDLPort} object here.
 368      *      We chose to receive this as a parameter instead of
 369      *      keeping {@link WSDLPort} in a message, just to save the storage.
 370      *
 371      *      <p>
 372      *      The implementation of this method involves caching the return
 373      *      value, so the behavior is undefined if multiple callers provide
 374      *      different {@link WSDLPort} objects, which is a bug of the caller.
 375      */
 376     public boolean isOneWay(@NotNull WSDLPort port) {
 377         if(isOneWay==null) {
 378             // we don't know, so compute.
 379             WSDLBoundOperation op = getOperation(port);
 380             if(op!=null)
 381                 isOneWay = op.getOperation().isOneWay();
 382             else
 383                 // the contract is to return true only when it's known to be one way.
 384                 isOneWay = false;
 385         }
 386         return isOneWay;
 387     }
 388 
 389     /**
 390      * Makes an assertion that this {@link Message} is
 391      * a request message for an one-way operation according
 392      * to the context WSDL.
 393      *
 394      * <p>
 395      * This method is really only intended to be invoked from within
 396      * the JAX-WS runtime, and not by any code building on top of it.
 397      *
 398      * <p>
 399      * This method can be invoked only when the caller "knows" what
 400      * WSDL says. Also, there's no point in invoking this method if the caller
 401      * is doing  {@code getOperation(port).getOperation().isOneWay()},
 402      * or sniffing the payload tag name.
 403      * In particular, this includes {@link DispatchImpl}.
 404      *
 405      * <p>
 406      * Once called, this allows {@link #isOneWay(WSDLPort)} method
 407      * to return a value quickly.
 408      *
 409      * @see #isOneWay(WSDLPort)
 410      */
 411     public final void assertOneWay(boolean value) {
 412         // if two callers make different assertions, that's a bug.
 413         // this is an assertion, not a runtime check because
 414         // nobody outside JAX-WS should be using this.
 415         assert isOneWay==null || isOneWay==value;
 416 
 417         isOneWay = value;
 418     }
 419 
 420 
 421     /**
 422      * Gets the local name of the payload element.
 423      *
 424      * @return
 425      *      null if a {@link Message} doesn't have any payload.
 426      */
 427     public abstract @Nullable String getPayloadLocalPart();
 428 
 429     /**
 430      * Gets the namespace URI of the payload element.
 431      *
 432      * @return
 433      *      null if a {@link Message} doesn't have any payload.
 434      */
 435     public abstract String getPayloadNamespaceURI();
 436     // I'm not putting @Nullable on it because doing null check on getPayloadLocalPart() should be suffice
 437 
 438     /**
 439      * Returns true if a {@link Message} has a payload.
 440      *
 441      * <p>
 442      * A message without a payload is a SOAP message that looks like:
 443      * <pre><xmp>
 444      * <S:Envelope>
 445      *   <S:Header>
 446      *     ...
 447      *   </S:Header>
 448      *   <S:Body />
 449      * </S:Envelope>
 450      * </xmp></pre>
 451      */
 452     public abstract boolean hasPayload();
 453 
 454     /**
 455      * Returns true if this message is a fault.
 456      *
 457      * <p>
 458      * Just a convenience method built on {@link #getPayloadNamespaceURI()}
 459      * and {@link #getPayloadLocalPart()}.
 460      */
 461     public boolean isFault() {
 462         // TODO: is SOAP version a property of a Message?
 463         // or is it defined by external factors?
 464         // how do I compare?
 465         String localPart = getPayloadLocalPart();
 466         if(localPart==null || !localPart.equals("Fault"))
 467             return false;
 468 
 469         String nsUri = getPayloadNamespaceURI();
 470         return nsUri.equals(SOAPVersion.SOAP_11.nsUri) || nsUri.equals(SOAPVersion.SOAP_12.nsUri);
 471     }
 472 
 473     /**
 474      * It gives S:Envelope/S:Body/S:Fault/detail 's first child's name. Should
 475      * be called for messages that have SOAP Fault.
 476      *
 477      * <p> This implementation is expensive so concrete implementations are
 478      * expected to override this one.
 479      *
 480      * @return first detail entry's name, if there is one
 481      *         else null
 482      */
 483     public @Nullable QName getFirstDetailEntryName() {
 484         assert isFault();
 485         Message msg = copy();
 486         try {
 487             SOAPFaultBuilder fault = SOAPFaultBuilder.create(msg);
 488             return fault.getFirstDetailEntryName();
 489         } catch (JAXBException e) {
 490             throw new WebServiceException(e);
 491         }
 492     }
 493 
 494     /**
 495      * Consumes this message including the envelope.
 496      * returns it as a {@link Source} object.
 497      */
 498     public abstract Source readEnvelopeAsSource();
 499 
 500 
 501     /**
 502      * Returns the payload as a {@link Source} object.
 503      *
 504      * This consumes the message.
 505      *
 506      * @return
 507      *      if there's no payload, this method returns null.
 508      */
 509     public abstract Source readPayloadAsSource();
 510 
 511     /**
 512      * Creates the equivalent {@link SOAPMessage} from this message.
 513      *
 514      * This consumes the message.
 515      *
 516      * @throws SOAPException
 517      *      if there's any error while creating a {@link SOAPMessage}.
 518      */
 519     public abstract SOAPMessage readAsSOAPMessage() throws SOAPException;
 520 
 521     /**
 522      * Creates the equivalent {@link SOAPMessage} from this message. It also uses
 523      * transport specific headers from Packet during the SOAPMessage construction
 524      * so that {@link SOAPMessage#getMimeHeaders()} gives meaningful transport
 525      * headers.
 526      *
 527      * This consumes the message.
 528      *
 529      * @throws SOAPException
 530      *      if there's any error while creating a {@link SOAPMessage}.
 531      */
 532     public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException {
 533         return readAsSOAPMessage();
 534     }
 535 
 536     public static Map<String, List<String>> getTransportHeaders(Packet packet) {
 537         return getTransportHeaders(packet, packet.getState().isInbound());
 538     }
 539 
 540     public static Map<String, List<String>> getTransportHeaders(Packet packet, boolean inbound) {
 541         Map<String, List<String>> headers = null;
 542         String key = inbound ? Packet.INBOUND_TRANSPORT_HEADERS : Packet.OUTBOUND_TRANSPORT_HEADERS;
 543         if (packet.supports(key)) {
 544             headers = (Map<String, List<String>>)packet.get(key);
 545         }
 546         return headers;
 547     }
 548 
 549     public static void addSOAPMimeHeaders(MimeHeaders mh, Map<String, List<String>> headers) {
 550         for(Map.Entry<String, List<String>> e : headers.entrySet()) {
 551             if (!e.getKey().equalsIgnoreCase("Content-Type")) {
 552                 for(String value : e.getValue()) {
 553                     mh.addHeader(e.getKey(), value);
 554                 }
 555             }
 556         }
 557     }
 558     /**
 559      * Reads the payload as a JAXB object by using the given unmarshaller.
 560      *
 561      * This consumes the message.
 562      *
 563      * @throws JAXBException
 564      *      If JAXB reports an error during the processing.
 565      */
 566     public abstract <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException;
 567 
 568     /**
 569      * Reads the payload as a JAXB object according to the given {@link Bridge}.
 570      *
 571      * This consumes the message.
 572      *
 573      * @deprecated
 574      * @return null
 575      *      if there's no payload.
 576      * @throws JAXBException
 577      *      If JAXB reports an error during the processing.
 578      */
 579     public abstract <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException;
 580 
 581     /**
 582      * Reads the payload as a Data-Bond object
 583      *
 584      * This consumes the message.
 585      *
 586      * @return null
 587      *      if there's no payload.
 588      * @throws JAXBException
 589      *      If JAXB reports an error during the processing.
 590      */
 591     public abstract <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException;
 592 
 593     /**
 594      * Reads the payload as a {@link XMLStreamReader}
 595      *
 596      * This consumes the message. The caller is encouraged to call
 597      * {@link XMLStreamReaderFactory#recycle(XMLStreamReader)} when finished using
 598      * the instance.
 599      *
 600      * @return
 601      *      If there's no payload, this method returns null.
 602      *      Otherwise always non-null valid {@link XMLStreamReader} that points to
 603      *      the payload tag name.
 604      */
 605     public abstract XMLStreamReader readPayload() throws XMLStreamException;
 606 
 607     /**
 608      * Marks the message as consumed, without actually reading the contents.
 609      *
 610      * <p>
 611      * This method provides an opportunity for implementations to reuse
 612      * any reusable resources needed for representing the payload.
 613      *
 614      * <p>
 615      * This method may not be called more than once since it may have
 616      * released the reusable resources.
 617      */
 618     public void consume() {}
 619 
 620     /**
 621      * Writes the payload to StAX.
 622      *
 623      * This method writes just the payload of the message to the writer.
 624      * This consumes the message.
 625      * The implementation will not write
 626      * {@link XMLStreamWriter#writeStartDocument()}
 627      * nor
 628      * {@link XMLStreamWriter#writeEndDocument()}
 629      *
 630      * <p>
 631      * If there's no payload, this method is no-op.
 632      *
 633      * @throws XMLStreamException
 634      *      If the {@link XMLStreamWriter} reports an error,
 635      *      or some other errors happen during the processing.
 636      */
 637     public abstract void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException;
 638 
 639     /**
 640      * Writes the whole SOAP message (but not attachments)
 641      * to the given writer.
 642      *
 643      * This consumes the message.
 644      *
 645      * @throws XMLStreamException
 646      *      If the {@link XMLStreamWriter} reports an error,
 647      *      or some other errors happen during the processing.
 648      */
 649     public abstract void writeTo(XMLStreamWriter sw) throws XMLStreamException;
 650 
 651     /**
 652      * Writes the whole SOAP envelope as SAX events.
 653      *
 654      * <p>
 655      * This consumes the message.
 656      *
 657      * @param contentHandler
 658      *      must not be nulll.
 659      * @param errorHandler
 660      *      must not be null.
 661      *      any error encountered during the SAX event production must be
 662      *      first reported to this error handler. Fatal errors can be then
 663      *      thrown as {@link SAXParseException}. {@link SAXException}s thrown
 664      *      from {@link ErrorHandler} should propagate directly through this method.
 665      */
 666     public abstract void writeTo( ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException;
 667 
 668     // TODO: do we need a method that reads payload as a fault?
 669     // do we want a separte streaming representation of fault?
 670     // or would SOAPFault in SAAJ do?
 671 
 672 
 673 
 674     /**
 675      * Creates a copy of a {@link Message}.
 676      *
 677      * <p>
 678      * This method creates a new {@link Message} whose header/payload/attachments/properties
 679      * are identical to this {@link Message}. Once created, the created {@link Message}
 680      * and the original {@link Message} behaves independently --- adding header/
 681      * attachment to one {@link Message} doesn't affect another {@link Message}
 682      * at all.
 683      *
 684      * <p>
 685      * This method does <b>NOT</b> consume a message.
 686      *
 687      * <p>
 688      * To enable efficient copy operations, there's a few restrictions on
 689      * how copied message can be used.
 690      *
 691      * <ol>
 692      *  <li>The original and the copy may not be
 693      *      used concurrently by two threads (this allows two {@link Message}s
 694      *      to share some internal resources, such as JAXB marshallers.)
 695      *      Note that it's OK for the original and the copy to be processed
 696      *      by two threads, as long as they are not concurrent.
 697      *
 698      *  <li>The copy has the same 'life scope'
 699      *      as the original (this allows shallower copy, such as
 700      *      JAXB beans wrapped in {@link JAXBMessage}.)
 701      * </ol>
 702      *
 703      * <p>
 704      * A 'life scope' of a message created during a message processing
 705      * in a pipeline is until a pipeline processes the next message.
 706      * A message cannot be kept beyond its life scope.
 707      *
 708      * (This experimental design is to allow message objects to be reused
 709      * --- feedback appreciated.)
 710      *
 711      *
 712      *
 713      * <h3>Design Rationale</h3>
 714      * <p>
 715      * Since a {@link Message} body is read-once, sometimes
 716      * (such as when you do fail-over, or WS-RM) you need to
 717      * create an idential copy of a {@link Message}.
 718      *
 719      * <p>
 720      * The actual copy operation depends on the layout
 721      * of the data in memory, hence it's best to be done by
 722      * the {@link Message} implementation itself.
 723      *
 724      * <p>
 725      * The restrictions placed on the use of copied {@link Message} can be
 726      * relaxed if necessary, but it will make the copy method more expensive.
 727      */
 728     // TODO: update the class javadoc with 'lifescope'
 729     // and move the discussion about life scope there.
 730     public abstract Message copy();
 731 
 732     /**
 733      * Retuns a unique id for the message. The id can be used for various things,
 734      * like debug assistance, logging, and MIME encoding(say for boundary).
 735      *
 736      * <p>
 737      * This method will check the existence of the addressing <MessageID> header,
 738      * and if present uses that value. Otherwise it generates one from UUID.random(),
 739      * and return it without adding a new header. But it doesn't add a <MessageID>
 740      * to the header list since we expect them to be added before calling this
 741      * method.
 742      *
 743      * <p>
 744      * Addressing tube will go do a separate verification on inbound
 745      * headers to make sure that <MessageID> header is present when it's
 746      * supposed to be.
 747      *
 748      * @param binding object created by {@link BindingID#createBinding()}
 749      *
 750      * @return unique id for the message
 751      * @deprecated
 752      */
 753     public @NotNull String getID(@NotNull WSBinding binding) {
 754         return getID(binding.getAddressingVersion(), binding.getSOAPVersion());
 755     }
 756 
 757     /**
 758      * Retuns a unique id for the message.
 759      * <p><p>
 760      * @see {@link #getID(com.sun.xml.internal.ws.api.WSBinding)} for detailed description.
 761      * @param av WS-Addressing version
 762      * @param sv SOAP version
 763      * @return unique id for the message
 764      * @deprecated
 765      */
 766     public @NotNull String getID(AddressingVersion av, SOAPVersion sv) {
 767         String uuid = null;
 768         if (av != null) {
 769             uuid = AddressingUtils.getMessageID(getHeaders(), av, sv);
 770         }
 771         if (uuid == null) {
 772             uuid = generateMessageID();
 773             getHeaders().add(new StringHeader(av.messageIDTag, uuid));
 774         }
 775         return uuid;
 776     }
 777 
 778     /**
 779      * Generates a UUID suitable for use as a MessageID value
 780      * @return generated UUID
 781      */
 782     public static String generateMessageID() {
 783         return "uuid:" + UUID.randomUUID().toString();
 784     }
 785 
 786     public SOAPVersion getSOAPVersion() {
 787         return null;
 788     }
 789 }