1 /* 2 * Copyright (c) 1997, 2014, 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 * <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 <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 <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 // See Packet for doc. 200 private boolean isProtocolMessage = false; 201 // next two are package protected - should only be used from Packet 202 boolean isProtocolMessage() { return isProtocolMessage; } 203 void setIsProtocolMessage() { isProtocolMessage = true; } 204 205 /** 206 * Returns true if headers are present in the message. 207 * 208 * @return 209 * true if headers are present. 210 */ 211 public abstract boolean hasHeaders(); 212 213 /** 214 * Gets all the headers of this message. 215 * 216 * <h3>Implementation Note</h3> 217 * <p> 218 * {@link Message} implementation is allowed to defer 219 * the construction of {@link MessageHeaders} object. So 220 * if you only want to check for the existence of any header 221 * element, use {@link #hasHeaders()}. 222 * 223 * @return 224 * always return the same non-null object. 225 */ 226 public abstract @NotNull MessageHeaders getHeaders(); 227 228 /** 229 * Gets the attachments of this message 230 * (attachments live outside a message.) 231 */ 232 public @NotNull AttachmentSet getAttachments() { 233 if (attachmentSet == null) { 234 attachmentSet = new AttachmentSetImpl(); 235 } 236 return attachmentSet; 237 } 238 239 /** 240 * Optimization hint for the derived class to check 241 * if we may have some attachments. 242 */ 243 protected boolean hasAttachments() { 244 return attachmentSet!=null; 245 } 246 247 protected AttachmentSet attachmentSet; 248 249 private WSDLBoundOperation operation = null; 250 251 private WSDLOperationMapping wsdlOperationMapping = null; 252 253 private MessageMetadata messageMetadata = null; 254 255 public void setMessageMedadata(MessageMetadata metadata) { 256 messageMetadata = metadata; 257 } 258 259 260 /** 261 * Returns the operation of which this message is an instance of. 262 * 263 * <p> 264 * This method relies on {@link WSDLBoundPortType#getOperation(String, String)} but 265 * it does so in an efficient way. 266 * 267 * @deprecated It is not always possible to uniquely identify the WSDL Operation from just the 268 * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()} 269 * to get it correctly. 270 * 271 * <p> 272 * This method works only for a request. A pipe can determine an operation for a request, 273 * and then keep it in a local variable to use it with a response, so there should be 274 * no need to find out operation from a response (besides, there might not be any response!). 275 * 276 * @param boundPortType 277 * This represents the port for which this message is used. 278 * Most {@link Pipe}s should get this information when they are created, 279 * since a pippeline always work against a particular type of {@link WSDLPort}. 280 * 281 * @return 282 * Null if the operation was not found. This is possible, for example when a protocol 283 * message is sent through a pipeline, or when we receive an invalid request on the server, 284 * or when we are on the client and the user appliation sends a random DOM through 285 * {@link Dispatch}, so this error needs to be handled gracefully. 286 */ 287 @Deprecated 288 public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLBoundPortType boundPortType) { 289 if (operation == null && messageMetadata != null) { 290 if (wsdlOperationMapping == null) wsdlOperationMapping = messageMetadata.getWSDLOperationMapping(); 291 if (wsdlOperationMapping != null) operation = wsdlOperationMapping.getWSDLBoundOperation(); 292 } 293 if(operation==null) 294 operation = boundPortType.getOperation(getPayloadNamespaceURI(),getPayloadLocalPart()); 295 return operation; 296 } 297 298 /** 299 * The same as {@link #getOperation(WSDLBoundPortType)} but 300 * takes {@link WSDLPort} for convenience. 301 * 302 * @deprecated It is not always possible to uniquely identify the WSDL Operation from just the 303 * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()} 304 * to get it correctly. 305 */ 306 @Deprecated 307 public final @Nullable WSDLBoundOperation getOperation(@NotNull WSDLPort port) { 308 return getOperation(port.getBinding()); 309 } 310 311 /** 312 * Returns the java Method of which this message is an instance of. 313 * 314 * It is not always possible to uniquely identify the WSDL Operation from just the 315 * information in the Message. Instead, Use {@link com.sun.xml.internal.ws.api.message.Packet#getWSDLOperation()} 316 * to get the QName of the associated wsdl operation correctly. 317 * 318 * <p> 319 * This method works only for a request. A pipe can determine a {@link Method} 320 * for a request, and then keep it in a local variable to use it with a response, 321 * so there should be no need to find out operation from a response (besides, 322 * there might not be any response!). 323 * 324 * @param seiModel 325 * This represents the java model for the endpoint 326 * Some server {@link Pipe}s would get this information when they are created. 327 * 328 * @return 329 * Null if there is no corresponding Method for this message. This is 330 * possible, for example when a protocol message is sent through a 331 * pipeline, or when we receive an invalid request on the server, 332 * or when we are on the client and the user appliation sends a random 333 * DOM through {@link Dispatch}, so this error needs to be handled 334 * gracefully. 335 */ 336 @Deprecated 337 public final @Nullable JavaMethod getMethod(@NotNull SEIModel seiModel) { 338 if (wsdlOperationMapping == null && messageMetadata != null) { 339 wsdlOperationMapping = messageMetadata.getWSDLOperationMapping(); 340 } 341 if (wsdlOperationMapping != null) { 342 return wsdlOperationMapping.getJavaMethod(); 343 } 344 //fall back to the original logic which could be incorrect ... 345 String localPart = getPayloadLocalPart(); 346 String nsUri; 347 if (localPart == null) { 348 localPart = ""; 349 nsUri = ""; 350 } else { 351 nsUri = getPayloadNamespaceURI(); 352 } 353 QName name = new QName(nsUri, localPart); 354 return seiModel.getJavaMethod(name); 355 } 356 357 private Boolean isOneWay; 358 359 /** 360 * Returns true if this message is a request message for a 361 * one way operation according to the given WSDL. False otherwise. 362 * 363 * <p> 364 * This method is functionally equivalent as doing 365 * {@code getOperation(port).getOperation().isOneWay()} 366 * (with proper null check and all.) But this method 367 * can sometimes work faster than that (for example, 368 * on the client side when used with SEI.) 369 * 370 * @param port 371 * {@link Message}s are always created under the context of 372 * one {@link WSDLPort} and they never go outside that context. 373 * Pass in that "governing" {@link WSDLPort} object here. 374 * We chose to receive this as a parameter instead of 375 * keeping {@link WSDLPort} in a message, just to save the storage. 376 * 377 * <p> 378 * The implementation of this method involves caching the return 379 * value, so the behavior is undefined if multiple callers provide 380 * different {@link WSDLPort} objects, which is a bug of the caller. 381 */ 382 public boolean isOneWay(@NotNull WSDLPort port) { 383 if(isOneWay==null) { 384 // we don't know, so compute. 385 WSDLBoundOperation op = getOperation(port); 386 if(op!=null) 387 isOneWay = op.getOperation().isOneWay(); 388 else 389 // the contract is to return true only when it's known to be one way. 390 isOneWay = false; 391 } 392 return isOneWay; 393 } 394 395 /** 396 * Makes an assertion that this {@link Message} is 397 * a request message for an one-way operation according 398 * to the context WSDL. 399 * 400 * <p> 401 * This method is really only intended to be invoked from within 402 * the JAX-WS runtime, and not by any code building on top of it. 403 * 404 * <p> 405 * This method can be invoked only when the caller "knows" what 406 * WSDL says. Also, there's no point in invoking this method if the caller 407 * is doing {@code getOperation(port).getOperation().isOneWay()}, 408 * or sniffing the payload tag name. 409 * In particular, this includes {@link DispatchImpl}. 410 * 411 * <p> 412 * Once called, this allows {@link #isOneWay(WSDLPort)} method 413 * to return a value quickly. 414 * 415 * @see #isOneWay(WSDLPort) 416 */ 417 public final void assertOneWay(boolean value) { 418 // if two callers make different assertions, that's a bug. 419 // this is an assertion, not a runtime check because 420 // nobody outside JAX-WS should be using this. 421 assert isOneWay==null || isOneWay==value; 422 423 isOneWay = value; 424 } 425 426 427 /** 428 * Gets the local name of the payload element. 429 * 430 * @return 431 * null if a {@link Message} doesn't have any payload. 432 */ 433 public abstract @Nullable String getPayloadLocalPart(); 434 435 /** 436 * Gets the namespace URI of the payload element. 437 * 438 * @return 439 * null if a {@link Message} doesn't have any payload. 440 */ 441 public abstract String getPayloadNamespaceURI(); 442 // I'm not putting @Nullable on it because doing null check on getPayloadLocalPart() should be suffice 443 444 /** 445 * Returns true if a {@link Message} has a payload. 446 * 447 * <p> 448 * A message without a payload is a SOAP message that looks like: 449 * <pre><xmp> 450 * <S:Envelope> 451 * <S:Header> 452 * ... 453 * </S:Header> 454 * <S:Body /> 455 * </S:Envelope> 456 * </xmp></pre> 457 */ 458 public abstract boolean hasPayload(); 459 460 /** 461 * Returns true if this message is a fault. 462 * 463 * <p> 464 * Just a convenience method built on {@link #getPayloadNamespaceURI()} 465 * and {@link #getPayloadLocalPart()}. 466 */ 467 public boolean isFault() { 468 // TODO: is SOAP version a property of a Message? 469 // or is it defined by external factors? 470 // how do I compare? 471 String localPart = getPayloadLocalPart(); 472 if(localPart==null || !localPart.equals("Fault")) 473 return false; 474 475 String nsUri = getPayloadNamespaceURI(); 476 return nsUri.equals(SOAPVersion.SOAP_11.nsUri) || nsUri.equals(SOAPVersion.SOAP_12.nsUri); 477 } 478 479 /** 480 * It gives S:Envelope/S:Body/S:Fault/detail 's first child's name. Should 481 * be called for messages that have SOAP Fault. 482 * 483 * <p> This implementation is expensive so concrete implementations are 484 * expected to override this one. 485 * 486 * @return first detail entry's name, if there is one 487 * else null 488 */ 489 public @Nullable QName getFirstDetailEntryName() { 490 assert isFault(); 491 Message msg = copy(); 492 try { 493 SOAPFaultBuilder fault = SOAPFaultBuilder.create(msg); 494 return fault.getFirstDetailEntryName(); 495 } catch (JAXBException e) { 496 throw new WebServiceException(e); 497 } 498 } 499 500 /** 501 * Consumes this message including the envelope. 502 * returns it as a {@link Source} object. 503 */ 504 public abstract Source readEnvelopeAsSource(); 505 506 507 /** 508 * Returns the payload as a {@link Source} object. 509 * 510 * This consumes the message. 511 * 512 * @return 513 * if there's no payload, this method returns null. 514 */ 515 public abstract Source readPayloadAsSource(); 516 517 /** 518 * Creates the equivalent {@link SOAPMessage} from this message. 519 * 520 * This consumes the message. 521 * 522 * @throws SOAPException 523 * if there's any error while creating a {@link SOAPMessage}. 524 */ 525 public abstract SOAPMessage readAsSOAPMessage() throws SOAPException; 526 527 /** 528 * Creates the equivalent {@link SOAPMessage} from this message. It also uses 529 * transport specific headers from Packet during the SOAPMessage construction 530 * so that {@link SOAPMessage#getMimeHeaders()} gives meaningful transport 531 * headers. 532 * 533 * This consumes the message. 534 * 535 * @throws SOAPException 536 * if there's any error while creating a {@link SOAPMessage}. 537 */ 538 public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException { 539 return readAsSOAPMessage(); 540 } 541 542 public static Map<String, List<String>> getTransportHeaders(Packet packet) { 543 return getTransportHeaders(packet, packet.getState().isInbound()); 544 } 545 546 public static Map<String, List<String>> getTransportHeaders(Packet packet, boolean inbound) { 547 Map<String, List<String>> headers = null; 548 String key = inbound ? Packet.INBOUND_TRANSPORT_HEADERS : Packet.OUTBOUND_TRANSPORT_HEADERS; 549 if (packet.supports(key)) { 550 headers = (Map<String, List<String>>)packet.get(key); 551 } 552 return headers; 553 } 554 555 public static void addSOAPMimeHeaders(MimeHeaders mh, Map<String, List<String>> headers) { 556 for(Map.Entry<String, List<String>> e : headers.entrySet()) { 557 if (!e.getKey().equalsIgnoreCase("Content-Type")) { 558 for(String value : e.getValue()) { 559 mh.addHeader(e.getKey(), value); 560 } 561 } 562 } 563 } 564 /** 565 * Reads the payload as a JAXB object by using the given unmarshaller. 566 * 567 * This consumes the message. 568 * 569 * @throws JAXBException 570 * If JAXB reports an error during the processing. 571 */ 572 public abstract <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException; 573 574 /** 575 * Reads the payload as a JAXB object according to the given {@link Bridge}. 576 * 577 * This consumes the message. 578 * 579 * @deprecated 580 * @return null 581 * if there's no payload. 582 * @throws JAXBException 583 * If JAXB reports an error during the processing. 584 */ 585 public abstract <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException; 586 587 /** 588 * Reads the payload as a Data-Bond object 589 * 590 * This consumes the message. 591 * 592 * @return null 593 * if there's no payload. 594 * @throws JAXBException 595 * If JAXB reports an error during the processing. 596 */ 597 public abstract <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException; 598 599 /** 600 * Reads the payload as a {@link XMLStreamReader} 601 * 602 * This consumes the message. The caller is encouraged to call 603 * {@link XMLStreamReaderFactory#recycle(XMLStreamReader)} when finished using 604 * the instance. 605 * 606 * @return 607 * If there's no payload, this method returns null. 608 * Otherwise always non-null valid {@link XMLStreamReader} that points to 609 * the payload tag name. 610 */ 611 public abstract XMLStreamReader readPayload() throws XMLStreamException; 612 613 /** 614 * Marks the message as consumed, without actually reading the contents. 615 * 616 * <p> 617 * This method provides an opportunity for implementations to reuse 618 * any reusable resources needed for representing the payload. 619 * 620 * <p> 621 * This method may not be called more than once since it may have 622 * released the reusable resources. 623 */ 624 public void consume() {} 625 626 /** 627 * Writes the payload to StAX. 628 * 629 * This method writes just the payload of the message to the writer. 630 * This consumes the message. 631 * The implementation will not write 632 * {@link XMLStreamWriter#writeStartDocument()} 633 * nor 634 * {@link XMLStreamWriter#writeEndDocument()} 635 * 636 * <p> 637 * If there's no payload, this method is no-op. 638 * 639 * @throws XMLStreamException 640 * If the {@link XMLStreamWriter} reports an error, 641 * or some other errors happen during the processing. 642 */ 643 public abstract void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException; 644 645 /** 646 * Writes the whole SOAP message (but not attachments) 647 * to the given writer. 648 * 649 * This consumes the message. 650 * 651 * @throws XMLStreamException 652 * If the {@link XMLStreamWriter} reports an error, 653 * or some other errors happen during the processing. 654 */ 655 public abstract void writeTo(XMLStreamWriter sw) throws XMLStreamException; 656 657 /** 658 * Writes the whole SOAP envelope as SAX events. 659 * 660 * <p> 661 * This consumes the message. 662 * 663 * @param contentHandler 664 * must not be nulll. 665 * @param errorHandler 666 * must not be null. 667 * any error encountered during the SAX event production must be 668 * first reported to this error handler. Fatal errors can be then 669 * thrown as {@link SAXParseException}. {@link SAXException}s thrown 670 * from {@link ErrorHandler} should propagate directly through this method. 671 */ 672 public abstract void writeTo( ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException; 673 674 // TODO: do we need a method that reads payload as a fault? 675 // do we want a separte streaming representation of fault? 676 // or would SOAPFault in SAAJ do? 677 678 679 680 /** 681 * Creates a copy of a {@link Message}. 682 * 683 * <p> 684 * This method creates a new {@link Message} whose header/payload/attachments/properties 685 * are identical to this {@link Message}. Once created, the created {@link Message} 686 * and the original {@link Message} behaves independently --- adding header/ 687 * attachment to one {@link Message} doesn't affect another {@link Message} 688 * at all. 689 * 690 * <p> 691 * This method does <b>NOT</b> consume a message. 692 * 693 * <p> 694 * To enable efficient copy operations, there's a few restrictions on 695 * how copied message can be used. 696 * 697 * <ol> 698 * <li>The original and the copy may not be 699 * used concurrently by two threads (this allows two {@link Message}s 700 * to share some internal resources, such as JAXB marshallers.) 701 * Note that it's OK for the original and the copy to be processed 702 * by two threads, as long as they are not concurrent. 703 * 704 * <li>The copy has the same 'life scope' 705 * as the original (this allows shallower copy, such as 706 * JAXB beans wrapped in {@link JAXBMessage}.) 707 * </ol> 708 * 709 * <p> 710 * A 'life scope' of a message created during a message processing 711 * in a pipeline is until a pipeline processes the next message. 712 * A message cannot be kept beyond its life scope. 713 * 714 * (This experimental design is to allow message objects to be reused 715 * --- feedback appreciated.) 716 * 717 * 718 * 719 * <h3>Design Rationale</h3> 720 * <p> 721 * Since a {@link Message} body is read-once, sometimes 722 * (such as when you do fail-over, or WS-RM) you need to 723 * create an idential copy of a {@link Message}. 724 * 725 * <p> 726 * The actual copy operation depends on the layout 727 * of the data in memory, hence it's best to be done by 728 * the {@link Message} implementation itself. 729 * 730 * <p> 731 * The restrictions placed on the use of copied {@link Message} can be 732 * relaxed if necessary, but it will make the copy method more expensive. 733 * 734 * <h3>IMPORTANT</h3> 735 * <p> WHEN YOU IMPLEMENT OR CHANGE A {@link .copy()} METHOD, YOU MUST 736 * USE THE {@link copyFrom(Message)} METHOD IN THE IMPLEMENTATION. 737 */ 738 // TODO: update the class javadoc with 'lifescope' 739 // and move the discussion about life scope there. 740 public abstract Message copy(); 741 742 /** 743 * The {@link Message#copy()} method is used as a shorthand 744 * throughout the codecase in place of calling a copy constructor. 745 * However, that shorthand make it difficult to have a concrete 746 * method here in the base to do common work. 747 * 748 * <p> Rather than have each {@code copy} method duplicate code, the 749 * following method is used in each {@code copy} implementation. 750 * It MUST be called. 751 * 752 * @return The Message that calls {@code copyFrom} inside the 753 * {@code copy} method after the copy constructor 754 */ 755 public final Message copyFrom(Message m) { 756 isProtocolMessage = m.isProtocolMessage; 757 return this; 758 } 759 760 /** 761 * Retuns a unique id for the message. The id can be used for various things, 762 * like debug assistance, logging, and MIME encoding(say for boundary). 763 * 764 * <p> 765 * This method will check the existence of the addressing <MessageID> header, 766 * and if present uses that value. Otherwise it generates one from UUID.random(), 767 * and return it without adding a new header. But it doesn't add a <MessageID> 768 * to the header list since we expect them to be added before calling this 769 * method. 770 * 771 * <p> 772 * Addressing tube will go do a separate verification on inbound 773 * headers to make sure that <MessageID> header is present when it's 774 * supposed to be. 775 * 776 * @param binding object created by {@link BindingID#createBinding()} 777 * 778 * @return unique id for the message 779 * @deprecated 780 */ 781 public @NotNull String getID(@NotNull WSBinding binding) { 782 return getID(binding.getAddressingVersion(), binding.getSOAPVersion()); 783 } 784 785 /** 786 * Retuns a unique id for the message. 787 * <p><p> 788 * @see {@link #getID(com.sun.xml.internal.ws.api.WSBinding)} for detailed description. 789 * @param av WS-Addressing version 790 * @param sv SOAP version 791 * @return unique id for the message 792 * @deprecated 793 */ 794 public @NotNull String getID(AddressingVersion av, SOAPVersion sv) { 795 String uuid = null; 796 if (av != null) { 797 uuid = AddressingUtils.getMessageID(getHeaders(), av, sv); 798 } 799 if (uuid == null) { 800 uuid = generateMessageID(); 801 getHeaders().add(new StringHeader(av.messageIDTag, uuid)); 802 } 803 return uuid; 804 } 805 806 /** 807 * Generates a UUID suitable for use as a MessageID value 808 * @return generated UUID 809 */ 810 public static String generateMessageID() { 811 return "uuid:" + UUID.randomUUID().toString(); 812 } 813 814 public SOAPVersion getSOAPVersion() { 815 return null; 816 } 817 }