author | avstepan |
Thu, 24 Sep 2015 18:26:42 +0300 | |
changeset 32795 | 5a5710ee05a0 |
parent 25871 | b80b84e87032 |
permissions | -rw-r--r-- |
12009 | 1 |
/* |
23782
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
2 |
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. |
12009 | 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; |
|
16791 | 37 |
import com.sun.xml.internal.ws.api.model.WSDLOperationMapping; |
12009 | 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; |
|
16791 | 60 |
import javax.xml.soap.MimeHeaders; |
12009 | 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; |
|
16791 | 72 |
import java.util.List; |
73 |
import java.util.Map; |
|
12009 | 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 |
||
23782
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
199 |
// See Packet for doc. |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
200 |
private boolean isProtocolMessage = false; |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
201 |
// next two are package protected - should only be used from Packet |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
202 |
boolean isProtocolMessage() { return isProtocolMessage; } |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
203 |
void setIsProtocolMessage() { isProtocolMessage = true; } |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
204 |
|
12009 | 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 |
|
16791 | 219 |
* the construction of {@link MessageHeaders} object. So |
12009 | 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 |
*/ |
|
16791 | 226 |
public abstract @NotNull MessageHeaders getHeaders(); |
12009 | 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 |
||
16791 | 251 |
private WSDLOperationMapping wsdlOperationMapping = null; |
252 |
||
253 |
private MessageMetadata messageMetadata = null; |
|
254 |
||
255 |
public void setMessageMedadata(MessageMetadata metadata) { |
|
256 |
messageMetadata = metadata; |
|
257 |
} |
|
258 |
||
259 |
||
12009 | 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) { |
|
16791 | 289 |
if (operation == null && messageMetadata != null) { |
290 |
if (wsdlOperationMapping == null) wsdlOperationMapping = messageMetadata.getWSDLOperationMapping(); |
|
291 |
if (wsdlOperationMapping != null) operation = wsdlOperationMapping.getWSDLBoundOperation(); |
|
292 |
} |
|
12009 | 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) { |
|
16791 | 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 ... |
|
12009 | 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: |
|
32795
5a5710ee05a0
8133651: replace some <tt> tags (obsolete in html5) in core-libs docs
avstepan
parents:
25871
diff
changeset
|
449 |
* <pre>{@code |
12009 | 450 |
* <S:Envelope> |
451 |
* <S:Header> |
|
452 |
* ... |
|
453 |
* </S:Header> |
|
454 |
* <S:Body /> |
|
455 |
* </S:Envelope> |
|
32795
5a5710ee05a0
8133651: replace some <tt> tags (obsolete in html5) in core-libs docs
avstepan
parents:
25871
diff
changeset
|
456 |
* }</pre> |
12009 | 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 |
||
16791 | 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 |
} |
|
12009 | 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. |
|
23782
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
733 |
* |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
734 |
* <h3>IMPORTANT</h3> |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
735 |
* <p> WHEN YOU IMPLEMENT OR CHANGE A {@link .copy()} METHOD, YOU MUST |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
736 |
* USE THE {@link copyFrom(Message)} METHOD IN THE IMPLEMENTATION. |
12009 | 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 |
/** |
|
23782
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
743 |
* The {@link Message#copy()} method is used as a shorthand |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
744 |
* throughout the codecase in place of calling a copy constructor. |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
745 |
* However, that shorthand make it difficult to have a concrete |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
746 |
* method here in the base to do common work. |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
747 |
* |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
748 |
* <p> Rather than have each {@code copy} method duplicate code, the |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
749 |
* following method is used in each {@code copy} implementation. |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
750 |
* It MUST be called. |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
751 |
* |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
752 |
* @return The Message that calls {@code copyFrom} inside the |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
753 |
* {@code copy} method after the copy constructor |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
754 |
*/ |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
755 |
public final Message copyFrom(Message m) { |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
756 |
isProtocolMessage = m.isProtocolMessage; |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
757 |
return this; |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
758 |
} |
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
759 |
|
953bfc3fbe31
8036030: Update JAX-WS RI integration to latest version
mkos
parents:
16791
diff
changeset
|
760 |
/** |
12009 | 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) { |
|
16791 | 797 |
uuid = AddressingUtils.getMessageID(getHeaders(), av, sv); |
12009 | 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 |
} |
|
16791 | 813 |
|
814 |
public SOAPVersion getSOAPVersion() { |
|
815 |
return null; |
|
816 |
} |
|
12009 | 817 |
} |