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

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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 }

mercurial