|
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.oracle.webservices.internal.api.message.ContentType; |
|
29 import com.oracle.webservices.internal.api.message.PropertySet; |
|
30 import com.sun.istack.internal.NotNull; |
|
31 import com.sun.istack.internal.Nullable; |
|
32 import com.sun.xml.internal.bind.marshaller.SAX2DOMEx; |
|
33 import com.sun.xml.internal.ws.addressing.WsaPropertyBag; |
|
34 import com.sun.xml.internal.ws.addressing.WsaServerTube; |
|
35 import com.sun.xml.internal.ws.addressing.WsaTubeHelper; |
|
36 import com.sun.xml.internal.ws.api.Component; |
|
37 import com.sun.xml.internal.ws.api.EndpointAddress; |
|
38 import com.sun.xml.internal.ws.api.SOAPVersion; |
|
39 import com.sun.xml.internal.ws.api.WSBinding; |
|
40 import com.sun.xml.internal.ws.api.addressing.AddressingVersion; |
|
41 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; |
|
42 import com.sun.xml.internal.ws.api.model.JavaMethod; |
|
43 import com.sun.xml.internal.ws.api.model.SEIModel; |
|
44 import com.sun.xml.internal.ws.api.model.WSDLOperationMapping; |
|
45 import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation; |
|
46 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; |
|
47 import com.sun.xml.internal.ws.api.pipe.Codec; |
|
48 import com.sun.xml.internal.ws.api.pipe.Tube; |
|
49 import com.sun.xml.internal.ws.api.server.Adapter; |
|
50 import com.sun.xml.internal.ws.api.server.TransportBackChannel; |
|
51 import com.sun.xml.internal.ws.api.server.WSEndpoint; |
|
52 import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate; |
|
53 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory; |
|
54 import com.sun.xml.internal.ws.client.*; |
|
55 import com.sun.xml.internal.ws.developer.JAXWSProperties; |
|
56 import com.sun.xml.internal.ws.encoding.MtomCodec; |
|
57 import com.sun.xml.internal.ws.message.RelatesToHeader; |
|
58 import com.sun.xml.internal.ws.message.StringHeader; |
|
59 import com.sun.xml.internal.ws.util.DOMUtil; |
|
60 import com.sun.xml.internal.ws.util.xml.XmlUtil; |
|
61 import com.sun.xml.internal.ws.wsdl.DispatchException; |
|
62 import com.sun.xml.internal.ws.wsdl.OperationDispatcher; |
|
63 import com.sun.xml.internal.ws.resources.AddressingMessages; |
|
64 |
|
65 |
|
66 import org.w3c.dom.Document; |
|
67 import org.w3c.dom.Element; |
|
68 import org.xml.sax.SAXException; |
|
69 |
|
70 import javax.xml.namespace.QName; |
|
71 import javax.xml.soap.SOAPException; |
|
72 import javax.xml.soap.SOAPMessage; |
|
73 import javax.xml.stream.XMLStreamWriter; |
|
74 import javax.xml.stream.XMLStreamException; |
|
75 import javax.xml.ws.BindingProvider; |
|
76 import javax.xml.ws.Dispatch; |
|
77 import javax.xml.ws.WebServiceContext; |
|
78 import javax.xml.ws.WebServiceException; |
|
79 import javax.xml.ws.handler.LogicalMessageContext; |
|
80 import javax.xml.ws.handler.MessageContext; |
|
81 import javax.xml.ws.handler.soap.SOAPMessageContext; |
|
82 import javax.xml.ws.soap.MTOMFeature; |
|
83 |
|
84 import java.util.*; |
|
85 import java.util.logging.Logger; |
|
86 import java.io.ByteArrayOutputStream; |
|
87 import java.io.IOException; |
|
88 import java.io.OutputStream; |
|
89 import java.nio.channels.WritableByteChannel; |
|
90 |
|
91 /** |
|
92 * Represents a container of a {@link Message}. |
|
93 * |
|
94 * <h2>What is a {@link Packet}?</h2> |
|
95 * <p> |
|
96 * A packet can be thought of as a frame/envelope/package that wraps |
|
97 * a {@link Message}. A packet keeps track of optional metadata (properties) |
|
98 * about a {@link Message} that doesn't go across the wire. |
|
99 * This roughly corresponds to {@link MessageContext} in the JAX-WS API. |
|
100 * |
|
101 * <p> |
|
102 * Usually a packet contains a {@link Message} in it, but sometimes |
|
103 * (such as for a reply of an one-way operation), a packet may |
|
104 * float around without a {@link Message} in it. |
|
105 * |
|
106 * |
|
107 * <a name="properties"></a> |
|
108 * <h2>Properties</h2> |
|
109 * <p> |
|
110 * Information frequently used inside the JAX-WS RI |
|
111 * is stored in the strongly-typed fields. Other information is stored |
|
112 * in terms of a generic {@link Map} (see |
|
113 * {@link #invocationProperties}.) |
|
114 * |
|
115 * <p> |
|
116 * Some properties need to be retained between request and response, |
|
117 * some don't. For strongly typed fields, this characteristic is |
|
118 * statically known for each of them, and propagation happens accordingly. |
|
119 * For generic information stored in {@link Map}, {@link #invocationProperties} |
|
120 * stores per-invocation scope information (which carries over to |
|
121 * the response.) |
|
122 * |
|
123 * <p> |
|
124 * This object is used as the backing store of {@link MessageContext}, and |
|
125 * {@link LogicalMessageContext} and {@link SOAPMessageContext} will |
|
126 * be delegating to this object for storing/retrieving values. |
|
127 * |
|
128 * |
|
129 * <h3>Relationship to request/response context</h3> |
|
130 * <p> |
|
131 * {@link BindingProvider#getRequestContext() Request context} is used to |
|
132 * seed the initial values of {@link Packet}. |
|
133 * Some of those values go to strongly-typed fields, and others go to |
|
134 * {@link #invocationProperties}, as they need to be retained in the reply message. |
|
135 * |
|
136 * <p> |
|
137 * Similarly, {@link BindingProvider#getResponseContext() response context} |
|
138 * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.) |
|
139 * by using properties from {@link #invocationProperties}, |
|
140 * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}. |
|
141 * IOW, properties added to {@link #invocationProperties} |
|
142 * are exposed to the response context by default. |
|
143 * |
|
144 * |
|
145 * |
|
146 * <h3>TODO</h3> |
|
147 * <ol> |
|
148 * <li>this class needs to be cloneable since Message is copiable. |
|
149 * <li>The three live views aren't implemented correctly. It will be |
|
150 * more work to do so, although I'm sure it's possible. |
|
151 * <li>{@link PropertySet.Property} annotation is to make it easy |
|
152 * for {@link MessageContext} to export properties on this object, |
|
153 * but it probably needs some clean up. |
|
154 * </ol> |
|
155 * |
|
156 * @author Kohsuke Kawaguchi |
|
157 */ |
|
158 public final class Packet |
|
159 // Packet must continue to extend/implement deprecated interfaces until downstream |
|
160 // usage is updated. |
|
161 extends com.oracle.webservices.internal.api.message.BaseDistributedPropertySet |
|
162 implements com.oracle.webservices.internal.api.message.MessageContext, MessageMetadata { |
|
163 |
|
164 /** |
|
165 * Creates a {@link Packet} that wraps a given {@link Message}. |
|
166 * |
|
167 * <p> |
|
168 * This method should be only used to create a fresh {@link Packet}. |
|
169 * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}. |
|
170 * |
|
171 * @param request |
|
172 * The request {@link Message}. Can be null. |
|
173 */ |
|
174 public Packet(Message request) { |
|
175 this(); |
|
176 this.message = request; |
|
177 if (message != null) message.setMessageMedadata(this); |
|
178 } |
|
179 |
|
180 /** |
|
181 * Creates an empty {@link Packet} that doesn't have any {@link Message}. |
|
182 */ |
|
183 public Packet() { |
|
184 this.invocationProperties = new HashMap<String, Object>(); |
|
185 } |
|
186 |
|
187 /** |
|
188 * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}. |
|
189 */ |
|
190 private Packet(Packet that) { |
|
191 relatePackets(that, true); |
|
192 this.invocationProperties = that.invocationProperties; |
|
193 } |
|
194 |
|
195 /** |
|
196 * Creates a copy of this {@link Packet}. |
|
197 * |
|
198 * @param copyMessage determines whether the {@link Message} from the original {@link Packet} should be copied as |
|
199 * well, or not. If the value is {@code false}, the {@link Message} in the copy of the {@link Packet} is {@code null}. |
|
200 * @return copy of the original packet |
|
201 */ |
|
202 public Packet copy(boolean copyMessage) { |
|
203 // the copy constructor is originally designed for creating a response packet, |
|
204 // but so far the implementation is usable for this purpose as well, so calling the copy constructor |
|
205 // to avoid code dupliation. |
|
206 Packet copy = new Packet(this); |
|
207 if (copyMessage && this.message != null) { |
|
208 copy.message = this.message.copy(); |
|
209 } |
|
210 if (copy.message != null) copy.message.setMessageMedadata(copy); |
|
211 return copy; |
|
212 } |
|
213 |
|
214 private Message message; |
|
215 |
|
216 /** |
|
217 * Gets the last {@link Message} set through {@link #setMessage(Message)}. |
|
218 * |
|
219 * @return may null. See the class javadoc for when it's null. |
|
220 */ |
|
221 public Message getMessage() { |
|
222 if (message != null && !(message instanceof MessageWrapper)) { |
|
223 message = new MessageWrapper(this, message); |
|
224 } |
|
225 return message; |
|
226 } |
|
227 |
|
228 public Message getInternalMessage() { |
|
229 return (message instanceof MessageWrapper)? ((MessageWrapper)message).delegate : message; |
|
230 } |
|
231 |
|
232 public WSBinding getBinding() { |
|
233 if (endpoint != null) { |
|
234 return endpoint.getBinding(); |
|
235 } |
|
236 if (proxy != null) { |
|
237 return (WSBinding) proxy.getBinding(); |
|
238 } |
|
239 return null; |
|
240 } |
|
241 /** |
|
242 * Sets a {@link Message} to this packet. |
|
243 * |
|
244 * @param message Can be null. |
|
245 */ |
|
246 public void setMessage(Message message) { |
|
247 this.message = message; |
|
248 if (message != null) this.message.setMessageMedadata(this); |
|
249 } |
|
250 |
|
251 private WSDLOperationMapping wsdlOperationMapping = null; |
|
252 |
|
253 private QName wsdlOperation; |
|
254 |
|
255 /** |
|
256 * Returns the QName of the wsdl operation associated with this packet. |
|
257 * <p/> |
|
258 * Information such as Payload QName, wsa:Action header, SOAPAction HTTP header are used depending on the features |
|
259 * enabled on the particular port. |
|
260 * |
|
261 * @return null if there is no WSDL model or |
|
262 * runtime cannot uniquely identify the wsdl operation from the information in the packet. |
|
263 */ |
|
264 @Property(MessageContext.WSDL_OPERATION) |
|
265 public final |
|
266 @Nullable |
|
267 QName getWSDLOperation() { |
|
268 if (wsdlOperation != null) return wsdlOperation; |
|
269 if ( wsdlOperationMapping == null) wsdlOperationMapping = getWSDLOperationMapping(); |
|
270 if ( wsdlOperationMapping != null ) wsdlOperation = wsdlOperationMapping.getOperationName(); |
|
271 return wsdlOperation; |
|
272 } |
|
273 |
|
274 public WSDLOperationMapping getWSDLOperationMapping() { |
|
275 if (wsdlOperationMapping != null) return wsdlOperationMapping; |
|
276 OperationDispatcher opDispatcher = null; |
|
277 if (endpoint != null) { |
|
278 opDispatcher = endpoint.getOperationDispatcher(); |
|
279 } else if (proxy != null) { |
|
280 opDispatcher = ((Stub) proxy).getOperationDispatcher(); |
|
281 } |
|
282 //OpDispatcher is null when there is no WSDLModel |
|
283 if (opDispatcher != null) { |
|
284 try { |
|
285 wsdlOperationMapping = opDispatcher.getWSDLOperationMapping(this); |
|
286 } catch (DispatchException e) { |
|
287 //Ignore, this might be a protocol message which may not have a wsdl operation |
|
288 //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for."); |
|
289 } |
|
290 } |
|
291 return wsdlOperationMapping; |
|
292 } |
|
293 |
|
294 /** |
|
295 * Set the wsdl operation to avoid lookup from other data. |
|
296 * This is useful in SEI based clients, where the WSDL operation can be known |
|
297 * from the associated {@link JavaMethod} |
|
298 * |
|
299 * @param wsdlOp QName |
|
300 */ |
|
301 public void setWSDLOperation(QName wsdlOp) { |
|
302 this.wsdlOperation = wsdlOp; |
|
303 } |
|
304 |
|
305 /** |
|
306 * True if this message came from a transport (IOW inbound), |
|
307 * and in paricular from a "secure" transport. A transport |
|
308 * needs to set this flag appropriately. |
|
309 * |
|
310 * <p> |
|
311 * This is a requirement from the security team. |
|
312 */ |
|
313 // TODO: expose this as a property |
|
314 public boolean wasTransportSecure; |
|
315 |
|
316 /** |
|
317 * Inbound transport headers are captured in a transport neutral way. |
|
318 * Transports are expected to fill this data after creating a Packet. |
|
319 * <p> |
|
320 * {@link SOAPMessage#getMimeHeaders()} would return these headers. |
|
321 */ |
|
322 public static final String INBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.inbound.transport.headers"; |
|
323 |
|
324 /** |
|
325 * Outbound transport headers are captured in a transport neutral way. |
|
326 * |
|
327 * <p> |
|
328 * Transports may choose to ignore certain headers that interfere with |
|
329 * its correct operation, such as |
|
330 * <tt>Content-Type</tt> and <tt>Content-Length</tt>. |
|
331 */ |
|
332 public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.outbound.transport.headers"; |
|
333 |
|
334 /** |
|
335 * |
|
336 */ |
|
337 public static final String HA_INFO = "com.sun.xml.internal.ws.api.message.packet.hainfo"; |
|
338 |
|
339 |
|
340 /** |
|
341 * This property holds the snapshot of HandlerConfiguration |
|
342 * at the time of invocation. |
|
343 * This property is used by MUPipe and HandlerPipe implementations. |
|
344 */ |
|
345 @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG) |
|
346 public HandlerConfiguration handlerConfig; |
|
347 |
|
348 /** |
|
349 * If a message originates from a proxy stub that implements |
|
350 * a port interface, this field is set to point to that object. |
|
351 * |
|
352 * TODO: who's using this property? |
|
353 */ |
|
354 @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY) |
|
355 public BindingProvider proxy; |
|
356 |
|
357 /** |
|
358 * Determines if the governing {@link Adapter} or {@link com.sun.xml.internal.ws.api.pipe.Fiber.CompletionCallback} |
|
359 * will handle delivering response messages targeted at non-anonymous endpoint |
|
360 * addresses. Prior to the introduction of this flag |
|
361 * the {@link WsaServerTube} would deliver non-anonymous responses. |
|
362 */ |
|
363 public boolean isAdapterDeliversNonAnonymousResponse; |
|
364 |
|
365 /** |
|
366 * During invocation of a client Stub or Dispatch a Packet is |
|
367 * created then the Stub's RequestContext is copied into the |
|
368 * Packet. On certain internal cases the Packet is created |
|
369 * *before* the invocation. In those cases we want the contents |
|
370 * of the Packet to take precedence when ever any key/value pairs |
|
371 * collide : if the Packet contains a value for a key use it, |
|
372 * otherwise copy as usual from Stub. |
|
373 */ |
|
374 public boolean packetTakesPriorityOverRequestContext = false; |
|
375 |
|
376 /** |
|
377 * The endpoint address to which this message is sent to. |
|
378 * |
|
379 * <p> |
|
380 * The JAX-WS spec allows this to be changed for each message, |
|
381 * so it's designed to be a property. |
|
382 * |
|
383 * <p> |
|
384 * Must not be null for a request message on the client. Otherwise |
|
385 * it's null. |
|
386 */ |
|
387 public EndpointAddress endpointAddress; |
|
388 |
|
389 /** |
|
390 * @deprecated |
|
391 * The programatic acccess should be done via |
|
392 * {@link #endpointAddress}. This is for JAX-WS client applications |
|
393 * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}. |
|
394 */ |
|
395 @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) |
|
396 public String getEndPointAddressString() { |
|
397 if (endpointAddress == null) { |
|
398 return null; |
|
399 } else { |
|
400 return endpointAddress.toString(); |
|
401 } |
|
402 } |
|
403 |
|
404 public void setEndPointAddressString(String s) { |
|
405 if (s == null) { |
|
406 this.endpointAddress = null; |
|
407 } else { |
|
408 this.endpointAddress = EndpointAddress.create(s); |
|
409 } |
|
410 } |
|
411 |
|
412 /** |
|
413 * The value of {@link ContentNegotiation#PROPERTY} |
|
414 * property. |
|
415 * <p/> |
|
416 * This property is used only on the client side. |
|
417 */ |
|
418 public ContentNegotiation contentNegotiation; |
|
419 |
|
420 @Property(ContentNegotiation.PROPERTY) |
|
421 public String getContentNegotiationString() { |
|
422 return (contentNegotiation != null) ? contentNegotiation.toString() : null; |
|
423 } |
|
424 |
|
425 public void setContentNegotiationString(String s) { |
|
426 if (s == null) { |
|
427 contentNegotiation = null; |
|
428 } else { |
|
429 try { |
|
430 contentNegotiation = ContentNegotiation.valueOf(s); |
|
431 } catch (IllegalArgumentException e) { |
|
432 // If the value is not recognized default to none |
|
433 contentNegotiation = ContentNegotiation.none; |
|
434 } |
|
435 } |
|
436 } |
|
437 |
|
438 /** |
|
439 * Gives a list of Reference Parameters in the Message |
|
440 * <p> |
|
441 * Headers which have attribute wsa:IsReferenceParameter="true" |
|
442 * This is not cached as one may reset the Message. |
|
443 *<p> |
|
444 */ |
|
445 @Property(MessageContext.REFERENCE_PARAMETERS) |
|
446 public |
|
447 @NotNull |
|
448 List<Element> getReferenceParameters() { |
|
449 Message msg = getMessage(); |
|
450 List<Element> refParams = new ArrayList<Element>(); |
|
451 if (msg == null) { |
|
452 return refParams; |
|
453 } |
|
454 MessageHeaders hl = msg.getHeaders(); |
|
455 for (Header h : hl.asList()) { |
|
456 String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter"); |
|
457 if (attr != null && (attr.equals("true") || attr.equals("1"))) { |
|
458 Document d = DOMUtil.createDom(); |
|
459 SAX2DOMEx s2d = new SAX2DOMEx(d); |
|
460 try { |
|
461 h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER); |
|
462 refParams.add((Element) d.getLastChild()); |
|
463 } catch (SAXException e) { |
|
464 throw new WebServiceException(e); |
|
465 } |
|
466 /* |
|
467 DOMResult result = new DOMResult(d); |
|
468 XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result); |
|
469 try { |
|
470 h.writeTo(domwriter); |
|
471 refParams.add((Element) result.getNode().getLastChild()); |
|
472 } catch (XMLStreamException e) { |
|
473 throw new WebServiceException(e); |
|
474 } |
|
475 */ |
|
476 } |
|
477 } |
|
478 return refParams; |
|
479 } |
|
480 |
|
481 /** |
|
482 * This method is for exposing header list through {@link PropertySet#get(Object)}, |
|
483 * for user applications, and should never be invoked directly from within the JAX-WS RI. |
|
484 */ |
|
485 @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY) |
|
486 /*package*/ MessageHeaders getHeaderList() { |
|
487 Message msg = getMessage(); |
|
488 if (msg == null) { |
|
489 return null; |
|
490 } |
|
491 return msg.getHeaders(); |
|
492 } |
|
493 |
|
494 /** |
|
495 * The list of MIME types that are acceptable to a receiver |
|
496 * of an outbound message. |
|
497 * |
|
498 * This property is used only on the server side. |
|
499 * |
|
500 * <p>The representation shall be that specified by the HTTP Accept |
|
501 * request-header field. |
|
502 * |
|
503 * <p>The list of content types will be obtained from the transport |
|
504 * meta-data of a inbound message in a request/response message exchange. |
|
505 * Hence this property will be set by the service-side transport pipe. |
|
506 */ |
|
507 public String acceptableMimeTypes; |
|
508 |
|
509 /** |
|
510 * When non-null, this object is consulted to |
|
511 * implement {@link WebServiceContext} methods |
|
512 * exposed to the user application. |
|
513 * |
|
514 * Used only on the server side. |
|
515 * |
|
516 * <p> |
|
517 * This property is set from the parameter |
|
518 * of {@link WSEndpoint.PipeHead#process}. |
|
519 */ |
|
520 public WebServiceContextDelegate webServiceContextDelegate; |
|
521 |
|
522 /** |
|
523 * Used only on the server side so that the transport |
|
524 * can close the connection early. |
|
525 * |
|
526 * <p> |
|
527 * This field can be null. While a message is being processed, |
|
528 * this field can be set explicitly to null, to prevent |
|
529 * future pipes from closing a transport (see {@link #keepTransportBackChannelOpen()}) |
|
530 * |
|
531 * <p> |
|
532 * This property is set from the parameter |
|
533 * of {@link WSEndpoint.PipeHead#process}. |
|
534 */ |
|
535 public |
|
536 @Nullable |
|
537 TransportBackChannel transportBackChannel; |
|
538 |
|
539 /** |
|
540 * Keeps the transport back channel open (by seeting {@link #transportBackChannel} to null.) |
|
541 * |
|
542 * @return |
|
543 * The previous value of {@link #transportBackChannel}. |
|
544 */ |
|
545 public TransportBackChannel keepTransportBackChannelOpen() { |
|
546 TransportBackChannel r = transportBackChannel; |
|
547 transportBackChannel = null; |
|
548 return r; |
|
549 } |
|
550 |
|
551 /** |
|
552 * The governing owner of this packet. On the service-side this is the {@link Adapter} and on the client it is the {@link Stub}. |
|
553 * |
|
554 */ |
|
555 public Component component; |
|
556 |
|
557 /** |
|
558 * The governing {@link WSEndpoint} in which this message is floating. |
|
559 * |
|
560 * <p> |
|
561 * This property is set if and only if this is on the server side. |
|
562 */ |
|
563 @Property(JAXWSProperties.WSENDPOINT) |
|
564 public WSEndpoint endpoint; |
|
565 |
|
566 /** |
|
567 * The value of the SOAPAction header associated with the message. |
|
568 * |
|
569 * <p> |
|
570 * For outgoing messages, the transport may sends out this value. |
|
571 * If this field is null, the transport may choose to send <tt>""</tt> |
|
572 * (quoted empty string.) |
|
573 * |
|
574 * For incoming messages, the transport will set this field. |
|
575 * If the incoming message did not contain the SOAPAction header, |
|
576 * the transport sets this field to null. |
|
577 * |
|
578 * <p> |
|
579 * If the value is non-null, it must be always in the quoted form. |
|
580 * The value can be null. |
|
581 * |
|
582 * <p> |
|
583 * Note that the way the transport sends this value out depends on |
|
584 * transport and SOAP version. |
|
585 * <p/> |
|
586 * For HTTP transport and SOAP 1.1, BP requires that SOAPAction |
|
587 * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2, |
|
588 * this is moved to the parameter of the "application/soap+xml". |
|
589 */ |
|
590 @Property(BindingProvider.SOAPACTION_URI_PROPERTY) |
|
591 public String soapAction; |
|
592 |
|
593 /** |
|
594 * A hint indicating that whether a transport should expect |
|
595 * a reply back from the server. |
|
596 * |
|
597 * <p> |
|
598 * This property is used on the client-side for |
|
599 * outbound messages, so that a pipeline |
|
600 * can communicate to the terminal (or intermediate) {@link Tube}s |
|
601 * about this knowledge. |
|
602 * |
|
603 * <p> |
|
604 * This property <b>MUST NOT</b> be used by 2-way transports |
|
605 * that have the transport back channel. Those transports |
|
606 * must always check a reply coming through the transport back |
|
607 * channel regardless of this value, and act accordingly. |
|
608 * (This is because the expectation of the client and |
|
609 * that of the server can be different, for example because |
|
610 * of a bug in user's configuration.) |
|
611 * |
|
612 * <p> |
|
613 * This property is for one-way transports, and more |
|
614 * specifically for the coordinator that correlates sent requests |
|
615 * and incoming replies, to decide whether to block |
|
616 * until a response is received. |
|
617 * |
|
618 * <p> |
|
619 * Also note that this property is related to |
|
620 * {@link WSDLOperation#isOneWay()} but not the same thing. |
|
621 * In fact in general, they are completely orthogonal. |
|
622 * |
|
623 * For example, the calling application can choose to invoke |
|
624 * {@link Dispatch#invoke(Object)} or {@link Dispatch#invokeOneWay(Object)} |
|
625 * with an operation (which determines the value of this property), |
|
626 * regardless of whether WSDL actually says it's one way or not. |
|
627 * So these two booleans can take any combinations. |
|
628 * |
|
629 * |
|
630 * <p> |
|
631 * When this property is {@link Boolean#FALSE}, it means that |
|
632 * the pipeline does not expect a reply from a server (and therefore |
|
633 * the correlator should not block for a reply message |
|
634 * -- if such a reply does arrive, it can be just ignored.) |
|
635 * |
|
636 * <p> |
|
637 * When this property is {@link Boolean#TRUE}, it means that |
|
638 * the pipeline expects a reply from a server (and therefore |
|
639 * the correlator should block to see if a reply message is received, |
|
640 * |
|
641 * <p> |
|
642 * This property is always set to {@link Boolean#TRUE} or |
|
643 * {@link Boolean#FALSE} when used on the request message |
|
644 * on the client side. |
|
645 * No other {@link Boolean} instances are allowed. |
|
646 * <p> |
|
647 * |
|
648 * In all other situations, this property is null. |
|
649 * |
|
650 */ |
|
651 @Property(BindingProviderProperties.ONE_WAY_OPERATION) |
|
652 public Boolean expectReply; |
|
653 |
|
654 |
|
655 /** |
|
656 * This property will be removed in a near future. |
|
657 * |
|
658 * <p> |
|
659 * A part of what this flag represented moved to |
|
660 * {@link #expectReply} and the other part was moved |
|
661 * to {@link Message#isOneWay(WSDLPort)}. Please update |
|
662 * your code soon, or risk breaking your build!! |
|
663 */ |
|
664 @Deprecated |
|
665 public Boolean isOneWay; |
|
666 |
|
667 /** |
|
668 * Indicates whether is invoking a synchronous pattern. If true, no |
|
669 * async client programming model (e.g. AsyncResponse or AsyncHandler) |
|
670 * were used to make the request that created this packet. |
|
671 */ |
|
672 public Boolean isSynchronousMEP; |
|
673 |
|
674 /** |
|
675 * Indicates whether a non-null AsyncHandler was given at the point of |
|
676 * making the request that created this packet. This flag can be used |
|
677 * by Tube implementations to decide how to react when isSynchronousMEP |
|
678 * is false. If true, the client gave a non-null AsyncHandler instance |
|
679 * at the point of request, and will be expecting a response on that |
|
680 * handler when this request has been processed. |
|
681 */ |
|
682 public Boolean nonNullAsyncHandlerGiven; |
|
683 |
|
684 /** |
|
685 * USE-CASE: |
|
686 * WS-AT is enabled, but there is no WSDL available. |
|
687 * If Packet.isRequestReplyMEP() is Boolean.TRUE then WS-AT should |
|
688 * add the TX context. |
|
689 * |
|
690 * This value is exposed to users via facades at higher abstraction layers. |
|
691 * The user should NEVER use Packet directly. |
|
692 * This value should ONLY be set by users. |
|
693 */ |
|
694 private Boolean isRequestReplyMEP; |
|
695 public Boolean isRequestReplyMEP() { return isRequestReplyMEP; } |
|
696 public void setRequestReplyMEP(final Boolean x) { isRequestReplyMEP = x; } |
|
697 |
|
698 /** |
|
699 * Lazily created set of handler-scope property names. |
|
700 * |
|
701 * <p> |
|
702 * We expect that this is only used when handlers are present |
|
703 * and they explicitly set some handler-scope values. |
|
704 * |
|
705 * @see #getHandlerScopePropertyNames(boolean) |
|
706 */ |
|
707 private Set<String> handlerScopePropertyNames; |
|
708 |
|
709 /** |
|
710 * Bag to capture properties that are available for the whole |
|
711 * message invocation (namely on both requests and responses.) |
|
712 * |
|
713 * <p> |
|
714 * These properties are copied from a request to a response. |
|
715 * This is where we keep properties that are set by handlers. |
|
716 * |
|
717 * <p> |
|
718 * See <a href="#properties">class javadoc</a> for more discussion. |
|
719 * |
|
720 * @see #getHandlerScopePropertyNames(boolean) |
|
721 */ |
|
722 public final Map<String, Object> invocationProperties; |
|
723 |
|
724 /** |
|
725 * Gets a {@link Set} that stores handler-scope properties. |
|
726 * |
|
727 * <p> |
|
728 * These properties will not be exposed to the response context. |
|
729 * Consequently, if a {@link Tube} wishes to hide a property |
|
730 * to {@link ResponseContext}, it needs to add the property name |
|
731 * to this set. |
|
732 * |
|
733 * @param readOnly |
|
734 * Return true if the caller only intends to read the value of this set. |
|
735 * Internally, the {@link Set} is allocated lazily, and this flag helps |
|
736 * optimizing the strategy. |
|
737 * |
|
738 * @return |
|
739 * always non-null, possibly empty set that stores property names. |
|
740 */ |
|
741 public final Set<String> getHandlerScopePropertyNames(boolean readOnly) { |
|
742 Set<String> o = this.handlerScopePropertyNames; |
|
743 if (o == null) { |
|
744 if (readOnly) { |
|
745 return Collections.emptySet(); |
|
746 } |
|
747 o = new HashSet<String>(); |
|
748 this.handlerScopePropertyNames = o; |
|
749 } |
|
750 return o; |
|
751 } |
|
752 |
|
753 /** |
|
754 * This method no longer works. |
|
755 * |
|
756 * @deprecated |
|
757 * Use {@link #getHandlerScopePropertyNames(boolean)}. |
|
758 * To be removed once Tango components are updated. |
|
759 */ |
|
760 public final Set<String> getApplicationScopePropertyNames(boolean readOnly) { |
|
761 assert false; |
|
762 return new HashSet<String>(); |
|
763 } |
|
764 |
|
765 /** |
|
766 * Creates a response {@link Packet} from a request packet ({@code this}). |
|
767 * |
|
768 * <p> |
|
769 * When a {@link Packet} for a reply is created, some properties need to be |
|
770 * copied over from a request to a response, and this method handles it correctly. |
|
771 * |
|
772 * @deprecated |
|
773 * Use createClientResponse(Message) for client side and |
|
774 * createServerResponse(Message, String) for server side response |
|
775 * creation. |
|
776 * |
|
777 * @param msg |
|
778 * The {@link Message} that represents a reply. Can be null. |
|
779 */ |
|
780 @Deprecated |
|
781 public Packet createResponse(Message msg) { |
|
782 Packet response = new Packet(this); |
|
783 response.setMessage(msg); |
|
784 return response; |
|
785 } |
|
786 |
|
787 /** |
|
788 * Creates a response {@link Packet} from a request packet ({@code this}). |
|
789 * |
|
790 * <p> |
|
791 * When a {@link Packet} for a reply is created, some properties need to be |
|
792 * copied over from a request to a response, and this method handles it correctly. |
|
793 * |
|
794 * @param msg |
|
795 * The {@link Message} that represents a reply. Can be null. |
|
796 */ |
|
797 public Packet createClientResponse(Message msg) { |
|
798 Packet response = new Packet(this); |
|
799 response.setMessage(msg); |
|
800 finishCreateRelateClientResponse(response); |
|
801 return response; |
|
802 } |
|
803 |
|
804 /** |
|
805 * For use cases that start with an existing Packet. |
|
806 */ |
|
807 public Packet relateClientResponse(final Packet response) { |
|
808 response.relatePackets(this, true); |
|
809 finishCreateRelateClientResponse(response); |
|
810 return response; |
|
811 } |
|
812 |
|
813 private void finishCreateRelateClientResponse(final Packet response) { |
|
814 response.soapAction = null; // de-initializing |
|
815 response.setState(State.ClientResponse); |
|
816 } |
|
817 |
|
818 /** |
|
819 * Creates a server-side response {@link Packet} from a request |
|
820 * packet ({@code this}). If WS-Addressing is enabled, a default Action |
|
821 * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort} |
|
822 * and <code>binding</code> {@link WSBinding}. |
|
823 * <p><p> |
|
824 * This method should be called to create application response messages |
|
825 * since they are associated with a {@link WSBinding} and {@link WSDLPort}. |
|
826 * For creating protocol messages that require a non-default Action, use |
|
827 * {@link #createServerResponse(Message, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, String)}. |
|
828 * |
|
829 * @param responseMessage The {@link Message} that represents a reply. Can be null. |
|
830 * @param wsdlPort The response WSDL port. |
|
831 * @param binding The response Binding. Cannot be null. |
|
832 * @return response packet |
|
833 */ |
|
834 public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { |
|
835 Packet r = createClientResponse(responseMessage); |
|
836 return relateServerResponse(r, wsdlPort, seiModel, binding); |
|
837 } |
|
838 |
|
839 /** |
|
840 * Copy all properties from ({@code this}) packet into a input {@link Packet} |
|
841 * @param response packet |
|
842 */ |
|
843 public void copyPropertiesTo(@Nullable Packet response){ |
|
844 relatePackets(response, false); |
|
845 } |
|
846 |
|
847 |
|
848 /** |
|
849 * A common method to make members related between input packet and this packet |
|
850 * |
|
851 * @param packet |
|
852 * @param isCopy 'true' means copying all properties from input packet; |
|
853 * 'false' means copying all properties from this packet to input packet. |
|
854 */ |
|
855 private void relatePackets(@Nullable Packet packet, boolean isCopy) |
|
856 { |
|
857 Packet request; |
|
858 Packet response; |
|
859 |
|
860 if (!isCopy) { //is relate |
|
861 request = this; |
|
862 response = packet; |
|
863 |
|
864 // processing specific properties |
|
865 response.soapAction = null; |
|
866 response.invocationProperties.putAll(request.invocationProperties); |
|
867 if (this.getState().equals(State.ServerRequest)) { |
|
868 response.setState(State.ServerResponse); |
|
869 } |
|
870 } else { //is copy constructor |
|
871 request = packet; |
|
872 response = this; |
|
873 |
|
874 // processing specific properties |
|
875 response.soapAction = request.soapAction; |
|
876 response.setState(request.getState()); |
|
877 } |
|
878 |
|
879 request.copySatelliteInto(response); |
|
880 response.isAdapterDeliversNonAnonymousResponse = request.isAdapterDeliversNonAnonymousResponse; |
|
881 response.handlerConfig = request.handlerConfig; |
|
882 response.handlerScopePropertyNames = request.handlerScopePropertyNames; |
|
883 response.contentNegotiation = request.contentNegotiation; |
|
884 response.wasTransportSecure = request.wasTransportSecure; |
|
885 response.transportBackChannel = request.transportBackChannel; |
|
886 response.endpointAddress = request.endpointAddress; |
|
887 response.wsdlOperation = request.wsdlOperation; |
|
888 response.wsdlOperationMapping = request.wsdlOperationMapping; |
|
889 response.acceptableMimeTypes = request.acceptableMimeTypes; |
|
890 response.endpoint = request.endpoint; |
|
891 response.proxy = request.proxy; |
|
892 response.webServiceContextDelegate = request.webServiceContextDelegate; |
|
893 response.expectReply = request.expectReply; |
|
894 response.component = request.component; |
|
895 response.mtomAcceptable = request.mtomAcceptable; |
|
896 response.mtomRequest = request.mtomRequest; |
|
897 // copy other properties that need to be copied. is there any? |
|
898 } |
|
899 |
|
900 |
|
901 public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) { |
|
902 relatePackets(r, false); |
|
903 r.setState(State.ServerResponse); |
|
904 AddressingVersion av = binding.getAddressingVersion(); |
|
905 // populate WS-A headers only if WS-A is enabled |
|
906 if (av == null) { |
|
907 return r; |
|
908 } |
|
909 |
|
910 if (getMessage() == null) { |
|
911 return r; |
|
912 } |
|
913 |
|
914 //populate WS-A headers only if the request has addressing headers |
|
915 String inputAction = AddressingUtils.getAction(getMessage().getHeaders(), av, binding.getSOAPVersion()); |
|
916 if (inputAction == null) { |
|
917 return r; |
|
918 } |
|
919 // if one-way, then dont populate any WS-A headers |
|
920 if (r.getMessage() == null || (wsdlPort != null && getMessage().isOneWay(wsdlPort))) { |
|
921 return r; |
|
922 } |
|
923 |
|
924 // otherwise populate WS-Addressing headers |
|
925 populateAddressingHeaders(binding, r, wsdlPort, seiModel); |
|
926 return r; |
|
927 } |
|
928 |
|
929 /** |
|
930 * Creates a server-side response {@link Packet} from a request |
|
931 * packet ({@code this}). If WS-Addressing is enabled, <code>action</code> |
|
932 * is used as Action Message Addressing Property. |
|
933 * <p><p> |
|
934 * This method should be called only for creating protocol response messages |
|
935 * that require a particular value of Action since they are not associated |
|
936 * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion} |
|
937 * and {@link SOAPVersion}. |
|
938 * |
|
939 * @param responseMessage The {@link Message} that represents a reply. Can be null. |
|
940 * @param addressingVersion The WS-Addressing version of the response message. |
|
941 * @param soapVersion The SOAP version of the response message. |
|
942 * @param action The response Action Message Addressing Property value. |
|
943 * @return response packet |
|
944 */ |
|
945 public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { |
|
946 Packet responsePacket = createClientResponse(responseMessage); |
|
947 responsePacket.setState(State.ServerResponse); |
|
948 // populate WS-A headers only if WS-A is enabled |
|
949 if (addressingVersion == null) { |
|
950 return responsePacket; |
|
951 } |
|
952 //populate WS-A headers only if the request has addressing headers |
|
953 String inputAction = AddressingUtils.getAction(this.getMessage().getHeaders(), addressingVersion, soapVersion); |
|
954 if (inputAction == null) { |
|
955 return responsePacket; |
|
956 } |
|
957 |
|
958 populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false); |
|
959 return responsePacket; |
|
960 } |
|
961 |
|
962 /** |
|
963 * Overwrites the {@link Message} of the response packet ({@code this}) by the given {@link Message}. |
|
964 * Unlike {@link #setMessage(Message)}, fill in the addressing headers correctly, and this process |
|
965 * requires the access to the request packet. |
|
966 * |
|
967 * <p> |
|
968 * This method is useful when the caller needs to swap a response message completely to a new one. |
|
969 * |
|
970 * @see #createServerResponse(Message, AddressingVersion, SOAPVersion, String) |
|
971 */ |
|
972 public void setResponseMessage(@NotNull Packet request, @Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) { |
|
973 Packet temp = request.createServerResponse(responseMessage, addressingVersion, soapVersion, action); |
|
974 setMessage(temp.getMessage()); |
|
975 } |
|
976 |
|
977 private void populateAddressingHeaders(Packet responsePacket, AddressingVersion av, SOAPVersion sv, String action, boolean mustUnderstand) { |
|
978 // populate WS-A headers only if WS-A is enabled |
|
979 if (av == null) return; |
|
980 |
|
981 // if one-way, then dont populate any WS-A headers |
|
982 if (responsePacket.getMessage() == null) |
|
983 return; |
|
984 |
|
985 MessageHeaders hl = responsePacket.getMessage().getHeaders(); |
|
986 |
|
987 WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class); |
|
988 Message msg = getMessage(); |
|
989 // wsa:To |
|
990 WSEndpointReference replyTo = null; |
|
991 Header replyToFromRequestMsg = AddressingUtils.getFirstHeader(msg.getHeaders(), av.replyToTag, true, sv); |
|
992 Header replyToFromResponseMsg = hl.get(av.toTag, false); |
|
993 boolean replaceToTag = true; |
|
994 try{ |
|
995 if (replyToFromRequestMsg != null){ |
|
996 replyTo = replyToFromRequestMsg.readAsEPR(av); |
|
997 } |
|
998 if (replyToFromResponseMsg != null && replyTo == null) { |
|
999 replaceToTag = false; |
|
1000 } |
|
1001 } catch (XMLStreamException e) { |
|
1002 throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); |
|
1003 } |
|
1004 if (replyTo == null) { |
|
1005 replyTo = AddressingUtils.getReplyTo(msg.getHeaders(), av, sv); |
|
1006 } |
|
1007 |
|
1008 // wsa:Action, add if the message doesn't already contain it, |
|
1009 // generally true for SEI case where there is SEIModel or WSDLModel |
|
1010 // false for Provider with no wsdl, Expects User to set the coresponding header on the Message. |
|
1011 if (AddressingUtils.getAction(responsePacket.getMessage().getHeaders(), av, sv) == null) { |
|
1012 //wsa:Action header is not set in the message, so use the wsa:Action passed as the parameter. |
|
1013 hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand)); |
|
1014 } |
|
1015 |
|
1016 // wsa:MessageID |
|
1017 if (responsePacket.getMessage().getHeaders().get(av.messageIDTag, false) == null) { |
|
1018 // if header doesn't exist, method getID creates a new random id |
|
1019 String newID = Message.generateMessageID(); |
|
1020 hl.add(new StringHeader(av.messageIDTag, newID)); |
|
1021 } |
|
1022 |
|
1023 // wsa:RelatesTo |
|
1024 String mid = null; |
|
1025 if (wpb != null) { |
|
1026 mid = wpb.getMessageID(); |
|
1027 } |
|
1028 if (mid == null) { |
|
1029 mid = AddressingUtils.getMessageID(msg.getHeaders(), av, sv); |
|
1030 } |
|
1031 if (mid != null) { |
|
1032 hl.addOrReplace(new RelatesToHeader(av.relatesToTag, mid)); |
|
1033 } |
|
1034 |
|
1035 |
|
1036 // populate reference parameters |
|
1037 WSEndpointReference refpEPR = null; |
|
1038 if (responsePacket.getMessage().isFault()) { |
|
1039 // choose FaultTo |
|
1040 if (wpb != null) { |
|
1041 refpEPR = wpb.getFaultToFromRequest(); |
|
1042 } |
|
1043 if (refpEPR == null) { |
|
1044 refpEPR = AddressingUtils.getFaultTo(msg.getHeaders(), av, sv); |
|
1045 } |
|
1046 // if FaultTo is null, then use ReplyTo |
|
1047 if (refpEPR == null) { |
|
1048 refpEPR = replyTo; |
|
1049 } |
|
1050 } else { |
|
1051 // choose ReplyTo |
|
1052 refpEPR = replyTo; |
|
1053 } |
|
1054 if (replaceToTag && refpEPR != null) { |
|
1055 hl.addOrReplace(new StringHeader(av.toTag, refpEPR.getAddress())); |
|
1056 refpEPR.addReferenceParametersToList(hl); |
|
1057 } |
|
1058 } |
|
1059 |
|
1060 private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) { |
|
1061 AddressingVersion addressingVersion = binding.getAddressingVersion(); |
|
1062 |
|
1063 if (addressingVersion == null) { |
|
1064 return; |
|
1065 } |
|
1066 |
|
1067 WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding); |
|
1068 String action = responsePacket.getMessage().isFault() ? |
|
1069 wsaHelper.getFaultAction(this, responsePacket) : |
|
1070 wsaHelper.getOutputAction(this); |
|
1071 if (action == null) { |
|
1072 LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message"); |
|
1073 return; |
|
1074 } |
|
1075 populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, AddressingVersion.isRequired(binding)); |
|
1076 } |
|
1077 |
|
1078 public String toShortString() { |
|
1079 return super.toString(); |
|
1080 } |
|
1081 |
|
1082 // For use only in a debugger |
|
1083 @Override |
|
1084 public String toString() { |
|
1085 StringBuilder buf = new StringBuilder(); |
|
1086 buf.append(super.toString()); |
|
1087 String content; |
|
1088 try { |
|
1089 Message msg = getMessage(); |
|
1090 if (msg != null) { |
|
1091 ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
|
1092 XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8"); |
|
1093 msg.copy().writeTo(xmlWriter); |
|
1094 xmlWriter.flush(); |
|
1095 xmlWriter.close(); |
|
1096 baos.flush(); |
|
1097 XMLStreamWriterFactory.recycle(xmlWriter); |
|
1098 |
|
1099 byte[] bytes = baos.toByteArray(); |
|
1100 //message = Messages.create(XMLStreamReaderFactory.create(null, new ByteArrayInputStream(bytes), "UTF-8", true)); |
|
1101 content = new String(bytes, "UTF-8"); |
|
1102 } else { |
|
1103 content = "<none>"; |
|
1104 } |
|
1105 } catch (Throwable t) { |
|
1106 throw new WebServiceException(t); |
|
1107 } |
|
1108 buf.append(" Content: ").append(content); |
|
1109 return buf.toString(); |
|
1110 } |
|
1111 |
|
1112 // completes TypedMap |
|
1113 private static final PropertyMap model; |
|
1114 |
|
1115 static { |
|
1116 model = parse(Packet.class); |
|
1117 } |
|
1118 |
|
1119 @Override |
|
1120 protected PropertyMap getPropertyMap() { |
|
1121 return model; |
|
1122 } |
|
1123 |
|
1124 public Map<String, Object> asMapIncludingInvocationProperties() { |
|
1125 final Map<String, Object> asMap = asMap(); |
|
1126 return new AbstractMap<String, Object>() { |
|
1127 @Override |
|
1128 public Object get(Object key) { |
|
1129 Object o = asMap.get(key); |
|
1130 if (o != null) |
|
1131 return o; |
|
1132 |
|
1133 return invocationProperties.get(key); |
|
1134 } |
|
1135 |
|
1136 @Override |
|
1137 public int size() { |
|
1138 return asMap.size() + invocationProperties.size(); |
|
1139 } |
|
1140 |
|
1141 @Override |
|
1142 public boolean containsKey(Object key) { |
|
1143 if (asMap.containsKey(key)) |
|
1144 return true; |
|
1145 return invocationProperties.containsKey(key); |
|
1146 } |
|
1147 |
|
1148 @Override |
|
1149 public Set<Entry<String, Object>> entrySet() { |
|
1150 final Set<Entry<String, Object>> asMapEntries = asMap.entrySet(); |
|
1151 final Set<Entry<String, Object>> ipEntries = invocationProperties.entrySet(); |
|
1152 |
|
1153 return new AbstractSet<Entry<String, Object>>() { |
|
1154 @Override |
|
1155 public Iterator<Entry<String, Object>> iterator() { |
|
1156 final Iterator<Entry<String, Object>> asMapIt = asMapEntries.iterator(); |
|
1157 final Iterator<Entry<String, Object>> ipIt = ipEntries.iterator(); |
|
1158 |
|
1159 return new Iterator<Entry<String, Object>>() { |
|
1160 @Override |
|
1161 public boolean hasNext() { |
|
1162 return asMapIt.hasNext() || ipIt.hasNext(); |
|
1163 } |
|
1164 |
|
1165 @Override |
|
1166 public java.util.Map.Entry<String, Object> next() { |
|
1167 if (asMapIt.hasNext()) |
|
1168 return asMapIt.next(); |
|
1169 return ipIt.next(); |
|
1170 } |
|
1171 |
|
1172 @Override |
|
1173 public void remove() { |
|
1174 throw new UnsupportedOperationException(); |
|
1175 } |
|
1176 }; |
|
1177 } |
|
1178 |
|
1179 @Override |
|
1180 public int size() { |
|
1181 return asMap.size() + invocationProperties.size(); |
|
1182 } |
|
1183 }; |
|
1184 } |
|
1185 |
|
1186 @Override |
|
1187 public Object put(String key, Object value) { |
|
1188 if (supports(key)) |
|
1189 return asMap.put(key, value); |
|
1190 |
|
1191 return invocationProperties.put(key, value); |
|
1192 } |
|
1193 |
|
1194 @Override |
|
1195 public void clear() { |
|
1196 asMap.clear(); |
|
1197 invocationProperties.clear(); |
|
1198 } |
|
1199 |
|
1200 @Override |
|
1201 public Object remove(Object key) { |
|
1202 if (supports(key)) |
|
1203 return asMap.remove(key); |
|
1204 |
|
1205 return invocationProperties.remove(key); |
|
1206 } |
|
1207 }; |
|
1208 } |
|
1209 |
|
1210 private static final Logger LOGGER = Logger.getLogger(Packet.class.getName()); |
|
1211 |
|
1212 @Override |
|
1213 public SOAPMessage getSOAPMessage() throws SOAPException { |
|
1214 return getAsSOAPMessage(); |
|
1215 } |
|
1216 |
|
1217 //TODO replace the message to a SAAJMEssage issue - JRFSAAJMessage or SAAJMessage? |
|
1218 @Override |
|
1219 public SOAPMessage getAsSOAPMessage() throws SOAPException { |
|
1220 Message msg = this.getMessage(); |
|
1221 if (msg == null) |
|
1222 return null; |
|
1223 if (msg instanceof MessageWritable) |
|
1224 ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); |
|
1225 return msg.readAsSOAPMessage(this, this.getState().isInbound()); |
|
1226 } |
|
1227 |
|
1228 public |
|
1229 Codec codec = null; |
|
1230 public Codec getCodec() { |
|
1231 if (codec != null) { |
|
1232 return codec; |
|
1233 } |
|
1234 if (endpoint != null) { |
|
1235 codec = endpoint.createCodec(); |
|
1236 } |
|
1237 WSBinding wsb = getBinding(); |
|
1238 if (wsb != null) { |
|
1239 codec = wsb.getBindingId().createEncoder(wsb); |
|
1240 } |
|
1241 return codec; |
|
1242 } |
|
1243 |
|
1244 @Override |
|
1245 public com.oracle.webservices.internal.api.message.ContentType writeTo( OutputStream out ) throws IOException { |
|
1246 Message msg = getInternalMessage(); |
|
1247 if (msg instanceof MessageWritable) { |
|
1248 ((MessageWritable) msg).setMTOMConfiguration(mtomFeature); |
|
1249 return ((MessageWritable)msg).writeTo(out); |
|
1250 } |
|
1251 return getCodec().encode(this, out); |
|
1252 } |
|
1253 |
|
1254 public com.oracle.webservices.internal.api.message.ContentType writeTo( WritableByteChannel buffer ) { |
|
1255 return getCodec().encode(this, buffer); |
|
1256 } |
|
1257 |
|
1258 private ContentType contentType; |
|
1259 |
|
1260 /** |
|
1261 * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true |
|
1262 * |
|
1263 * Used on server-side, for encoding the repsonse. |
|
1264 */ |
|
1265 private Boolean mtomRequest; |
|
1266 |
|
1267 /** |
|
1268 * Based on request's Accept header this is set. |
|
1269 * Currently only set if MTOMFeature is enabled. |
|
1270 * |
|
1271 * Should be used on server-side, for encoding the response. |
|
1272 */ |
|
1273 private Boolean mtomAcceptable; |
|
1274 |
|
1275 private MTOMFeature mtomFeature; |
|
1276 |
|
1277 public Boolean getMtomRequest() { |
|
1278 return mtomRequest; |
|
1279 } |
|
1280 |
|
1281 public void setMtomRequest(Boolean mtomRequest) { |
|
1282 this.mtomRequest = mtomRequest; |
|
1283 } |
|
1284 |
|
1285 public Boolean getMtomAcceptable() { |
|
1286 return mtomAcceptable; |
|
1287 } |
|
1288 |
|
1289 Boolean checkMtomAcceptable; |
|
1290 public void checkMtomAcceptable() { |
|
1291 if (checkMtomAcceptable == null) { |
|
1292 if (acceptableMimeTypes == null || isFastInfosetDisabled) { |
|
1293 checkMtomAcceptable = false; |
|
1294 } else { |
|
1295 checkMtomAcceptable = (acceptableMimeTypes.indexOf(MtomCodec.XOP_XML_MIME_TYPE) != -1); |
|
1296 // StringTokenizer st = new StringTokenizer(acceptableMimeTypes, ","); |
|
1297 // while (st.hasMoreTokens()) { |
|
1298 // final String token = st.nextToken().trim(); |
|
1299 // if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) { |
|
1300 // mtomAcceptable = true; |
|
1301 // } |
|
1302 // } |
|
1303 // if (mtomAcceptable == null) mtomAcceptable = false; |
|
1304 } |
|
1305 } |
|
1306 mtomAcceptable = checkMtomAcceptable; |
|
1307 } |
|
1308 |
|
1309 private Boolean fastInfosetAcceptable; |
|
1310 |
|
1311 public Boolean getFastInfosetAcceptable(String fiMimeType) { |
|
1312 if (fastInfosetAcceptable == null) { |
|
1313 if (acceptableMimeTypes == null || isFastInfosetDisabled) { |
|
1314 fastInfosetAcceptable = false; |
|
1315 } else { |
|
1316 fastInfosetAcceptable = (acceptableMimeTypes.indexOf(fiMimeType) != -1); |
|
1317 } |
|
1318 // if (accept == null || isFastInfosetDisabled) return false; |
|
1319 // |
|
1320 // StringTokenizer st = new StringTokenizer(accept, ","); |
|
1321 // while (st.hasMoreTokens()) { |
|
1322 // final String token = st.nextToken().trim(); |
|
1323 // if (token.equalsIgnoreCase(fiMimeType)) { |
|
1324 // return true; |
|
1325 // } |
|
1326 // } |
|
1327 // return false; |
|
1328 } |
|
1329 return fastInfosetAcceptable; |
|
1330 } |
|
1331 |
|
1332 |
|
1333 public void setMtomFeature(MTOMFeature mtomFeature) { |
|
1334 this.mtomFeature = mtomFeature; |
|
1335 } |
|
1336 |
|
1337 public MTOMFeature getMtomFeature() { |
|
1338 //If we have a binding, use that in preference to an explicitly |
|
1339 //set MTOMFeature |
|
1340 WSBinding binding = getBinding(); |
|
1341 if (binding != null) { |
|
1342 return binding.getFeature(MTOMFeature.class); |
|
1343 } |
|
1344 return mtomFeature; |
|
1345 } |
|
1346 |
|
1347 @Override |
|
1348 public com.oracle.webservices.internal.api.message.ContentType getContentType() { |
|
1349 if (contentType == null) { |
|
1350 contentType = getInternalContentType(); |
|
1351 } |
|
1352 if (contentType == null) { |
|
1353 contentType = getCodec().getStaticContentType(this); |
|
1354 } |
|
1355 if (contentType == null) { |
|
1356 //TODO write to buffer |
|
1357 } |
|
1358 return contentType; |
|
1359 } |
|
1360 |
|
1361 public ContentType getInternalContentType() { |
|
1362 Message msg = getInternalMessage(); |
|
1363 if (msg instanceof MessageWritable) { |
|
1364 return ((MessageWritable)msg).getContentType(); |
|
1365 } |
|
1366 return contentType; |
|
1367 } |
|
1368 |
|
1369 public void setContentType(ContentType contentType) { |
|
1370 this.contentType = contentType; |
|
1371 } |
|
1372 |
|
1373 public enum Status { |
|
1374 Request, Response, Unknown; |
|
1375 public boolean isRequest() { return Request.equals(this); } |
|
1376 public boolean isResponse() { return Response.equals(this); } |
|
1377 } |
|
1378 |
|
1379 public enum State { |
|
1380 ServerRequest(true), ClientRequest(false), ServerResponse(false), ClientResponse(true); |
|
1381 private boolean inbound; |
|
1382 State(boolean inbound) { |
|
1383 this.inbound = inbound; |
|
1384 } |
|
1385 public boolean isInbound() { |
|
1386 return inbound; |
|
1387 } |
|
1388 } |
|
1389 |
|
1390 // private Status status = Status.Unknown; |
|
1391 |
|
1392 //Default state is ServerRequest - some custom adapters may not set the value of state |
|
1393 //upon server request - all other code paths should set it |
|
1394 private State state = State.ServerRequest; |
|
1395 |
|
1396 // public Status getStatus() { return status; } |
|
1397 |
|
1398 public State getState() { return state; } |
|
1399 public void setState(State state) { this.state = state; } |
|
1400 |
|
1401 public boolean shouldUseMtom() { |
|
1402 if (getState().isInbound()) { |
|
1403 return isMtomContentType(); |
|
1404 } else { |
|
1405 return shouldUseMtomOutbound(); |
|
1406 } |
|
1407 } |
|
1408 |
|
1409 private boolean shouldUseMtomOutbound() { |
|
1410 //Use the getter to make sure all the logic is executed correctly |
|
1411 MTOMFeature myMtomFeature = getMtomFeature(); |
|
1412 if(myMtomFeature != null && myMtomFeature.isEnabled()) { |
|
1413 //On client, always use XOP encoding if MTOM is enabled |
|
1414 //On Server, mtomAcceptable and mtomRequest will be set - use XOP encoding |
|
1415 //if either request is XOP encoded (mtomRequest) or |
|
1416 //client accepts XOP encoding (mtomAcceptable) |
|
1417 if (getMtomAcceptable() == null && getMtomRequest() == null) { |
|
1418 return true; |
|
1419 } else { |
|
1420 if (getMtomAcceptable() != null && getMtomAcceptable() && getState().equals(State.ServerResponse)) { |
|
1421 return true; |
|
1422 } |
|
1423 if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ServerResponse)) { |
|
1424 return true; |
|
1425 } |
|
1426 if (getMtomRequest() != null && getMtomRequest() && getState().equals(State.ClientRequest)) { |
|
1427 return true; |
|
1428 } |
|
1429 } |
|
1430 } |
|
1431 return false; |
|
1432 } |
|
1433 |
|
1434 private boolean isMtomContentType() { |
|
1435 return (getInternalContentType() != null) && |
|
1436 (getInternalContentType().getContentType().contains("application/xop+xml")); |
|
1437 } |
|
1438 |
|
1439 /** |
|
1440 * @deprecated |
|
1441 */ |
|
1442 public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { |
|
1443 super.addSatellite(satellite); |
|
1444 } |
|
1445 |
|
1446 /** |
|
1447 * @deprecated |
|
1448 */ |
|
1449 public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) { |
|
1450 super.addSatellite(keyClass, satellite); |
|
1451 } |
|
1452 |
|
1453 /** |
|
1454 * @deprecated |
|
1455 */ |
|
1456 public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) { |
|
1457 super.copySatelliteInto(r); |
|
1458 } |
|
1459 |
|
1460 /** |
|
1461 * @deprecated |
|
1462 */ |
|
1463 public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) { |
|
1464 super.removeSatellite(satellite); |
|
1465 } |
|
1466 |
|
1467 /** |
|
1468 * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable |
|
1469 */ |
|
1470 private boolean isFastInfosetDisabled; |
|
1471 |
|
1472 public void setFastInfosetDisabled(boolean b) { |
|
1473 isFastInfosetDisabled = b; |
|
1474 } |
|
1475 } |