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