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

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.ws.api.message;
27
28 import com.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 }

mercurial