1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.ws.api.message;
27
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
31 import com.sun.xml.internal.ws.addressing.WsaPropertyBag;
32 import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
33 import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException;
34 import com.sun.xml.internal.ws.api.*;
35 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
36 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
37 import com.sun.xml.internal.ws.api.message.saaj.SAAJFactory;
38 import com.sun.xml.internal.ws.api.model.JavaMethod;
39 import com.sun.xml.internal.ws.api.model.SEIModel;
40 import com.sun.xml.internal.ws.api.model.wsdl.WSDLOperation;
41 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
42 import com.sun.xml.internal.ws.api.pipe.Codec;
43 import com.sun.xml.internal.ws.api.pipe.Tube;
44 import com.sun.xml.internal.ws.api.server.Adapter;
45 import com.sun.xml.internal.ws.api.server.TransportBackChannel;
46 import com.sun.xml.internal.ws.api.server.WSEndpoint;
47 import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate;
48 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory;
49 import com.sun.xml.internal.ws.client.*;
50 import com.sun.xml.internal.ws.developer.JAXWSProperties;
51 import com.sun.xml.internal.ws.message.RelatesToHeader;
52 import com.sun.xml.internal.ws.message.StringHeader;
53 import com.sun.xml.internal.ws.transport.http.WSHTTPConnection;
54 import com.sun.xml.internal.ws.message.saaj.SAAJMessage;
55 import com.sun.xml.internal.ws.server.WSEndpointImpl;
56 import com.sun.xml.internal.ws.util.DOMUtil;
57 import com.sun.xml.internal.ws.util.xml.XmlUtil;
58 import com.sun.xml.internal.ws.wsdl.DispatchException;
59 import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
60
61 import com.sun.xml.internal.org.jvnet.ws.message.ContentType;
62 import org.w3c.dom.Document;
63 import org.w3c.dom.Element;
64 import org.xml.sax.SAXException;
65
66 import javax.xml.namespace.QName;
67 import javax.xml.soap.SOAPException;
68 import javax.xml.soap.SOAPMessage;
69 import javax.xml.stream.XMLStreamWriter;
70 import javax.xml.ws.BindingProvider;
71 import javax.xml.ws.Dispatch;
72 import javax.xml.ws.WebServiceContext;
73 import javax.xml.ws.WebServiceException;
74 import javax.xml.ws.handler.LogicalMessageContext;
75 import javax.xml.ws.handler.MessageContext;
76 import javax.xml.ws.handler.soap.SOAPMessageContext;
77 import java.util.*;
78 import java.util.logging.Logger;
79 import java.io.ByteArrayOutputStream;
80 import java.io.IOException;
81 import java.io.OutputStream;
82 import java.nio.ByteBuffer;
83 import java.nio.channels.WritableByteChannel;
84
85 /**
86 * Represents a container of a {@link Message}.
87 *
88 * <h2>What is a {@link Packet}?</h2>
89 * <p>
90 * A packet can be thought of as a frame/envelope/package that wraps
91 * a {@link Message}. A packet keeps track of optional metadata (properties)
92 * about a {@link Message} that doesn't go across the wire.
93 * This roughly corresponds to {@link MessageContext} in the JAX-WS API.
94 *
95 * <p>
96 * Usually a packet contains a {@link Message} in it, but sometimes
97 * (such as for a reply of an one-way operation), a packet may
98 * float around without a {@link Message} in it.
99 *
100 *
101 * <a name="properties"></a>
102 * <h2>Properties</h2>
125 * {@link BindingProvider#getRequestContext() Request context} is used to
126 * seed the initial values of {@link Packet}.
127 * Some of those values go to strongly-typed fields, and others go to
128 * {@link #invocationProperties}, as they need to be retained in the reply message.
129 *
130 * <p>
131 * Similarly, {@link BindingProvider#getResponseContext() response context}
132 * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.)
133 * by using properties from {@link #invocationProperties},
134 * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}.
135 * IOW, properties added to {@link #invocationProperties}
136 * are exposed to the response context by default.
137 *
138 *
139 *
140 * <h3>TODO</h3>
141 * <ol>
142 * <li>this class needs to be cloneable since Message is copiable.
143 * <li>The three live views aren't implemented correctly. It will be
144 * more work to do so, although I'm sure it's possible.
145 * <li>{@link Property} annotation is to make it easy
146 * for {@link MessageContext} to export properties on this object,
147 * but it probably needs some clean up.
148 * </ol>
149 *
150 * @author Kohsuke Kawaguchi
151 */
152 public final class Packet
153 extends DistributedPropertySet
154 implements com.sun.xml.internal.org.jvnet.ws.message.MessageContext
155 {
156
157 /**
158 * Creates a {@link Packet} that wraps a given {@link Message}.
159 *
160 * <p>
161 * This method should be only used to create a fresh {@link Packet}.
162 * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}.
163 *
164 * @param request
165 * The request {@link Message}. Can be null.
166 */
167 public Packet(Message request) {
168 this();
169 this.message = request;
170 }
171
172 /**
173 * Creates an empty {@link Packet} that doesn't have any {@link Message}.
174 */
175 public Packet() {
176 this.invocationProperties = new HashMap<String, Object>();
177 }
178
179 /**
180 * Used by {@link #createResponse(Message)} and {@link #copy(boolean)}.
181 */
182 private Packet(Packet that) {
183 that.copySatelliteInto((DistributedPropertySet) this);
184 this.handlerConfig = that.handlerConfig;
185 this.invocationProperties = that.invocationProperties;
186 this.handlerScopePropertyNames = that.handlerScopePropertyNames;
187 this.contentNegotiation = that.contentNegotiation;
188 this.wasTransportSecure = that.wasTransportSecure;
189 this.transportBackChannel = that.transportBackChannel;
190 this.endpointAddress = that.endpointAddress;
191 this.isAdapterDeliversNonAnonymousResponse = that.isAdapterDeliversNonAnonymousResponse;
192 this.wsdlOperation = that.wsdlOperation;
193 this.acceptableMimeTypes = that.acceptableMimeTypes;
194 this.endpoint = that.endpoint;
195 this.proxy = that.proxy;
196 this.webServiceContextDelegate = that.webServiceContextDelegate;
197 this.soapAction = that.soapAction;
198 this.expectReply = that.expectReply;
199 this.component = that.component;
200 // copy other properties that need to be copied. is there any?
201 }
202
203 /**
204 * Creates a copy of this {@link Packet}.
205 *
206 * @param copyMessage determines whether the {@link Message} from the original {@link Packet} should be copied as
207 * well, or not. If the value is {@code false}, the {@link Message} in the copy of the {@link Packet} is {@code null}.
208 * @return copy of the original packet
209 */
210 public Packet copy(boolean copyMessage) {
211 // the copy constructor is originally designed for creating a response packet,
212 // but so far the implementation is usable for this purpose as well, so calling the copy constructor
213 // to avoid code dupliation.
214 Packet copy = new Packet(this);
215 if (copyMessage && this.message != null) {
216 copy.message = this.message.copy();
217 }
218
219 return copy;
220 }
221
222 private Message message;
223
224 /**
225 * Gets the last {@link Message} set through {@link #setMessage(Message)}.
226 *
227 * @return may null. See the class javadoc for when it's null.
228 */
229 public Message getMessage() {
230 return message;
231 }
232
233 public WSBinding getBinding() {
234 if (endpoint != null)
235 return endpoint.getBinding();
236 if (proxy != null)
237 return (WSBinding) proxy.getBinding();
238 return null;
239 }
240 /**
241 * Sets a {@link Message} to this packet.
242 *
243 * @param message Can be null.
244 */
245 public void setMessage(Message message) {
246 this.message = message;
247 }
248
249 private QName wsdlOperation;
250
251 /**
252 * Returns the QName of the wsdl operation associated with this packet.
253 * <p/>
254 * Information such as Payload QName, wsa:Action header, SOAPAction HTTP header are used depending on the features
255 * enabled on the particular port.
256 *
257 * @return null if there is no WSDL model or
258 * runtime cannot uniquely identify the wsdl operation from the information in the packet.
259 */
260 @com.sun.xml.internal.ws.api.PropertySet.Property(MessageContext.WSDL_OPERATION)
261 public final
262 @Nullable
263 QName getWSDLOperation() {
264 if (wsdlOperation != null)
265 return wsdlOperation;
266
267 OperationDispatcher opDispatcher = null;
268 if (endpoint != null) {
269 opDispatcher = ((WSEndpointImpl) endpoint).getOperationDispatcher();
270 } else if (proxy != null) {
271 opDispatcher = ((Stub) proxy).getOperationDispatcher();
272 }
273 //OpDispatcher is null when there is no WSDLModel
274 if (opDispatcher != null) {
275 try {
276 wsdlOperation = opDispatcher.getWSDLOperationQName(this);
277 } catch (DispatchException e) {
278 //Ignore, this might be a protocol message which may not have a wsdl operation
279 //LOGGER.info("Cannot resolve wsdl operation that this Packet is targeted for.");
280 }
281 }
282 return wsdlOperation;
283 }
284
285 /**
286 * Set the wsdl operation to avoid lookup from other data.
287 * This is useful in SEI based clients, where the WSDL operation can be known
288 * from the associated {@link JavaMethod}
289 *
290 * @param wsdlOp QName
291 */
292 public void setWSDLOperation(QName wsdlOp) {
293 this.wsdlOperation = wsdlOp;
294 }
295
296 /**
297 * True if this message came from a transport (IOW inbound),
298 * and in paricular from a "secure" transport. A transport
299 * needs to set this flag appropriately.
300 *
301 * <p>
302 * This is a requirement from the security team.
316 * Outbound transport headers are captured in a transport neutral way.
317 *
318 * <p>
319 * Transports may choose to ignore certain headers that interfere with
320 * its correct operation, such as
321 * <tt>Content-Type</tt> and <tt>Content-Length</tt>.
322 */
323 public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.internal.ws.api.message.packet.outbound.transport.headers";
324
325 /**
326 *
327 */
328 public static final String HA_INFO = "com.sun.xml.internal.ws.api.message.packet.hainfo";
329
330
331 /**
332 * This property holds the snapshot of HandlerConfiguration
333 * at the time of invocation.
334 * This property is used by MUPipe and HandlerPipe implementations.
335 */
336 @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG)
337 public HandlerConfiguration handlerConfig;
338
339 /**
340 * If a message originates from a proxy stub that implements
341 * a port interface, this field is set to point to that object.
342 *
343 * TODO: who's using this property?
344 */
345 @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY)
346 public BindingProvider proxy;
347
348 /**
349 * Determines if the governing {@link Adapter} or {@link Fiber.CompletionCallback} will handle delivering
350 * response messages targeted at non-anonymous endpoint addresses. Prior to the introduction of this
351 * flag the {@link WsaServerTube} would deliver non-anonymous responses.
352 */
353 public boolean isAdapterDeliversNonAnonymousResponse;
354
355 /**
356 * The endpoint address to which this message is sent to.
357 *
358 * <p>
359 * The JAX-WS spec allows this to be changed for each message,
360 * so it's designed to be a property.
361 *
362 * <p>
363 * Must not be null for a request message on the client. Otherwise
364 * it's null.
365 */
366 public EndpointAddress endpointAddress;
367
368 /**
369 * @deprecated
370 * The programatic acccess should be done via
371 * {@link #endpointAddress}. This is for JAX-WS client applications
372 * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}.
373 */
374 @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)
375 public String getEndPointAddressString() {
376 if (endpointAddress == null)
377 return null;
378 else
379 return endpointAddress.toString();
380 }
381
382 public void setEndPointAddressString(String s) {
383 if (s == null)
384 this.endpointAddress = null;
385 else
386 this.endpointAddress = EndpointAddress.create(s);
387 }
388
389 /**
390 * The value of {@link ContentNegotiation#PROPERTY}
391 * property.
392 * <p/>
393 * This property is used only on the client side.
394 */
395 public ContentNegotiation contentNegotiation;
396
397 @com.sun.xml.internal.ws.api.PropertySet.Property(ContentNegotiation.PROPERTY)
398 public String getContentNegotiationString() {
399 return (contentNegotiation != null) ? contentNegotiation.toString() : null;
400 }
401
402 public void setContentNegotiationString(String s) {
403 if (s == null)
404 contentNegotiation = null;
405 else {
406 try {
407 contentNegotiation = ContentNegotiation.valueOf(s);
408 } catch (IllegalArgumentException e) {
409 // If the value is not recognized default to none
410 contentNegotiation = ContentNegotiation.none;
411 }
412 }
413 }
414
415 /**
416 * Gives a list of Reference Parameters in the Message
417 * <p>
418 * Headers which have attribute wsa:IsReferenceParameter="true"
419 * This is not cached as one may reset the Message.
420 *<p>
421 */
422 @com.sun.xml.internal.ws.api.PropertySet.Property(MessageContext.REFERENCE_PARAMETERS)
423 public
424 @NotNull
425 List<Element> getReferenceParameters() {
426 List<Element> refParams = new ArrayList<Element>();
427 if (message == null) {
428 return refParams;
429 }
430 HeaderList hl = message.getHeaders();
431 for (Header h : hl) {
432 String attr = h.getAttribute(AddressingVersion.W3C.nsUri, "IsReferenceParameter");
433 if (attr != null && (attr.equals("true") || attr.equals("1"))) {
434 Document d = DOMUtil.createDom();
435 SAX2DOMEx s2d = new SAX2DOMEx(d);
436 try {
437 h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER);
438 refParams.add((Element) d.getLastChild());
439 } catch (SAXException e) {
440 throw new WebServiceException(e);
441 }
442 /*
443 DOMResult result = new DOMResult(d);
444 XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result);
445 try {
446 h.writeTo(domwriter);
447 refParams.add((Element) result.getNode().getLastChild());
448 } catch (XMLStreamException e) {
449 throw new WebServiceException(e);
450 }
451 */
452 }
453 }
454 return refParams;
455 }
456
457 /**
458 * @deprecated
459 * This method is for exposing header list through {@link PropertySet#get(Object)},
460 * for user applications, and should never be invoked directly from within the JAX-WS RI.
461 */
462 @com.sun.xml.internal.ws.api.PropertySet.Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)
463 /*package*/ HeaderList getHeaderList() {
464 if (message == null) return null;
465 return message.getHeaders();
466 }
467
468 /**
469 * The list of MIME types that are acceptable to a receiver
470 * of an outbound message.
471 *
472 * This property is used only on the server side.
473 *
474 * <p>The representation shall be that specified by the HTTP Accept
475 * request-header field.
476 *
477 * <p>The list of content types will be obtained from the transport
478 * meta-data of a inbound message in a request/response message exchange.
479 * Hence this property will be set by the service-side transport pipe.
480 */
481 public String acceptableMimeTypes;
482
483 /**
484 * When non-null, this object is consulted to
485 * implement {@link WebServiceContext} methods
517 * The previous value of {@link #transportBackChannel}.
518 */
519 public TransportBackChannel keepTransportBackChannelOpen() {
520 TransportBackChannel r = transportBackChannel;
521 transportBackChannel = null;
522 return r;
523 }
524
525 /**
526 * The governing owner of this packet. On the service-side this is the {@link Adapter} and on the client it is the {@link Stub}.
527 *
528 */
529 public Component component;
530
531 /**
532 * The governing {@link WSEndpoint} in which this message is floating.
533 *
534 * <p>
535 * This property is set if and only if this is on the server side.
536 */
537 @com.sun.xml.internal.ws.api.PropertySet.Property(JAXWSProperties.WSENDPOINT)
538 public WSEndpoint endpoint;
539
540 /**
541 * The value of the SOAPAction header associated with the message.
542 *
543 * <p>
544 * For outgoing messages, the transport may sends out this value.
545 * If this field is null, the transport may choose to send <tt>""</tt>
546 * (quoted empty string.)
547 *
548 * For incoming messages, the transport will set this field.
549 * If the incoming message did not contain the SOAPAction header,
550 * the transport sets this field to null.
551 *
552 * <p>
553 * If the value is non-null, it must be always in the quoted form.
554 * The value can be null.
555 *
556 * <p>
557 * Note that the way the transport sends this value out depends on
558 * transport and SOAP version.
559 * <p/>
560 * For HTTP transport and SOAP 1.1, BP requires that SOAPAction
561 * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2,
562 * this is moved to the parameter of the "application/soap+xml".
563 */
564 @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProvider.SOAPACTION_URI_PROPERTY)
565 public String soapAction;
566
567 /**
568 * A hint indicating that whether a transport should expect
569 * a reply back from the server.
570 *
571 * <p>
572 * This property is used on the client-side for
573 * outbound messages, so that a pipeline
574 * can communicate to the terminal (or intermediate) {@link Tube}s
575 * about this knowledge.
576 *
577 * <p>
578 * This property <b>MUST NOT</b> be used by 2-way transports
579 * that have the transport back channel. Those transports
580 * must always check a reply coming through the transport back
581 * channel regardless of this value, and act accordingly.
582 * (This is because the expectation of the client and
583 * that of the server can be different, for example because
584 * of a bug in user's configuration.)
605 * When this property is {@link Boolean#FALSE}, it means that
606 * the pipeline does not expect a reply from a server (and therefore
607 * the correlator should not block for a reply message
608 * -- if such a reply does arrive, it can be just ignored.)
609 *
610 * <p>
611 * When this property is {@link Boolean#TRUE}, it means that
612 * the pipeline expects a reply from a server (and therefore
613 * the correlator should block to see if a reply message is received,
614 *
615 * <p>
616 * This property is always set to {@link Boolean#TRUE} or
617 * {@link Boolean#FALSE} when used on the request message
618 * on the client side.
619 * No other {@link Boolean} instances are allowed.
620 * <p>
621 *
622 * In all other situations, this property is null.
623 *
624 */
625 @com.sun.xml.internal.ws.api.PropertySet.Property(BindingProviderProperties.ONE_WAY_OPERATION)
626 public Boolean expectReply;
627
628
629 /**
630 * This property will be removed in a near future.
631 *
632 * <p>
633 * A part of what this flag represented moved to
634 * {@link #expectReply} and the other part was moved
635 * to {@link Message#isOneWay(WSDLPort)}. Please update
636 * your code soon, or risk breaking your build!!
637 */
638 @Deprecated
639 public Boolean isOneWay;
640
641 /**
642 * Indicates whether is invoking a synchronous pattern. If true, no
643 * async client programming model (e.g. AsyncResponse or AsyncHandler)
644 * were used to make the request that created this packet.
645 */
646 public Boolean isSynchronousMEP;
647
648 /**
649 * Indicates whether a non-null AsyncHandler was given at the point of
650 * making the request that created this packet. This flag can be used
651 * by Tube implementations to decide how to react when isSynchronousMEP
652 * is false. If true, the client gave a non-null AsyncHandler instance
653 * at the point of request, and will be expecting a response on that
654 * handler when this request has been processed.
655 */
656 public Boolean nonNullAsyncHandlerGiven;
657
658 /**
659 * Lazily created set of handler-scope property names.
660 *
661 * <p>
662 * We expect that this is only used when handlers are present
663 * and they explicitly set some handler-scope values.
664 *
665 * @see #getHandlerScopePropertyNames(boolean)
666 */
667 private Set<String> handlerScopePropertyNames;
668
669 /**
670 * Bag to capture properties that are available for the whole
671 * message invocation (namely on both requests and responses.)
672 *
673 * <p>
674 * These properties are copied from a request to a response.
675 * This is where we keep properties that are set by handlers.
676 *
677 * <p>
678 * See <a href="#properties">class javadoc</a> for more discussion.
684 /**
685 * Gets a {@link Set} that stores handler-scope properties.
686 *
687 * <p>
688 * These properties will not be exposed to the response context.
689 * Consequently, if a {@link Tube} wishes to hide a property
690 * to {@link ResponseContext}, it needs to add the property name
691 * to this set.
692 *
693 * @param readOnly
694 * Return true if the caller only intends to read the value of this set.
695 * Internally, the {@link Set} is allocated lazily, and this flag helps
696 * optimizing the strategy.
697 *
698 * @return
699 * always non-null, possibly empty set that stores property names.
700 */
701 public final Set<String> getHandlerScopePropertyNames(boolean readOnly) {
702 Set<String> o = this.handlerScopePropertyNames;
703 if (o == null) {
704 if (readOnly)
705 return Collections.emptySet();
706 o = new HashSet<String>();
707 this.handlerScopePropertyNames = o;
708 }
709 return o;
710 }
711
712 /**
713 * This method no longer works.
714 *
715 * @deprecated
716 * Use {@link #getHandlerScopePropertyNames(boolean)}.
717 * To be removed once Tango components are updated.
718 */
719 public final Set<String> getApplicationScopePropertyNames(boolean readOnly) {
720 assert false;
721 return new HashSet<String>();
722 }
723
724 /**
725 * Creates a response {@link Packet} from a request packet ({@code this}).
738 */
739 @Deprecated
740 public Packet createResponse(Message msg) {
741 Packet response = new Packet(this);
742 response.setMessage(msg);
743 return response;
744 }
745
746 /**
747 * Creates a response {@link Packet} from a request packet ({@code this}).
748 *
749 * <p>
750 * When a {@link Packet} for a reply is created, some properties need to be
751 * copied over from a request to a response, and this method handles it correctly.
752 *
753 * @param msg
754 * The {@link Message} that represents a reply. Can be null.
755 */
756 public Packet createClientResponse(Message msg) {
757 Packet response = new Packet(this);
758 response.soapAction = null; // de-initializing
759 response.setMessage(msg);
760 return response;
761 }
762
763 /**
764 * Creates a server-side response {@link Packet} from a request
765 * packet ({@code this}). If WS-Addressing is enabled, a default Action
766 * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort}
767 * and <code>binding</code> {@link WSBinding}.
768 * <p><p>
769 * This method should be called to create application response messages
770 * since they are associated with a {@link WSBinding} and {@link WSDLPort}.
771 * For creating protocol messages that require a non-default Action, use
772 * {@link #createServerResponse(Message, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, String)}.
773 *
774 * @param responseMessage The {@link Message} that represents a reply. Can be null.
775 * @param wsdlPort The response WSDL port.
776 * @param binding The response Binding. Cannot be null.
777 * @return response packet
778 */
779 public Packet createServerResponse(@Nullable Message responseMessage, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) {
780 Packet r = createClientResponse(responseMessage);
781
782 AddressingVersion av = binding.getAddressingVersion();
783 // populate WS-A headers only if WS-A is enabled
784 if (av == null)
785 return r;
786 //populate WS-A headers only if the request has addressing headers
787 String inputAction = this.getMessage().getHeaders().getAction(av, binding.getSOAPVersion());
788 if (inputAction == null) {
789 return r;
790 }
791 // if one-way, then dont populate any WS-A headers
792 if (responseMessage == null || (wsdlPort != null && message.isOneWay(wsdlPort)))
793 return r;
794
795 // otherwise populate WS-Addressing headers
796 populateAddressingHeaders(binding, r, wsdlPort, seiModel);
797 return r;
798 }
799
800
801 public Packet relateServerResponse(@Nullable Packet r, @Nullable WSDLPort wsdlPort, @Nullable SEIModel seiModel, @NotNull WSBinding binding) {
802 copySatelliteInto((DistributedPropertySet) r);
803 r.soapAction = null;
804 r.handlerConfig = this.handlerConfig;
805 r.invocationProperties.putAll(this.invocationProperties);
806 r.handlerScopePropertyNames = this.handlerScopePropertyNames;
807 r.contentNegotiation = this.contentNegotiation;
808 r.wasTransportSecure = this.wasTransportSecure;
809 r.endpointAddress = this.endpointAddress;
810 r.wsdlOperation = this.wsdlOperation;
811
812 r.acceptableMimeTypes = this.acceptableMimeTypes;
813 r.endpoint = this.endpoint;
814 r.proxy = this.proxy;
815 r.webServiceContextDelegate = this.webServiceContextDelegate;
816 r.expectReply = this.expectReply;
817
818 AddressingVersion av = binding.getAddressingVersion();
819 // populate WS-A headers only if WS-A is enabled
820 if (av == null)
821 return r;
822 //populate WS-A headers only if the request has addressing headers
823 String inputAction = this.getMessage().getHeaders().getAction(av, binding.getSOAPVersion());
824 if (inputAction == null) {
825 return r;
826 }
827 // if one-way, then dont populate any WS-A headers
828 if (r.getMessage() == null || (wsdlPort != null && message.isOneWay(wsdlPort)))
829 return r;
830
831 // otherwise populate WS-Addressing headers
832 populateAddressingHeaders(binding, r, wsdlPort, seiModel);
833 return r;
834 }
835
836 /**
837 * Creates a server-side response {@link Packet} from a request
838 * packet ({@code this}). If WS-Addressing is enabled, <code>action</code>
839 * is used as Action Message Addressing Property.
840 * <p><p>
841 * This method should be called only for creating protocol response messages
842 * that require a particular value of Action since they are not associated
843 * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion}
844 * and {@link SOAPVersion}.
845 *
846 * @param responseMessage The {@link Message} that represents a reply. Can be null.
847 * @param addressingVersion The WS-Addressing version of the response message.
848 * @param soapVersion The SOAP version of the response message.
849 * @param action The response Action Message Addressing Property value.
850 * @return response packet
851 */
852 public Packet createServerResponse(@Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) {
853 Packet responsePacket = createClientResponse(responseMessage);
854
855 // populate WS-A headers only if WS-A is enabled
856 if (addressingVersion == null)
857 return responsePacket;
858 //populate WS-A headers only if the request has addressing headers
859 String inputAction = this.getMessage().getHeaders().getAction(addressingVersion, soapVersion);
860 if (inputAction == null) {
861 return responsePacket;
862 }
863
864 populateAddressingHeaders(responsePacket, addressingVersion, soapVersion, action, false);
865 return responsePacket;
866 }
867
868 /**
869 * Overwrites the {@link Message} of the response packet ({@code this}) by the given {@link Message}.
870 * Unlike {@link #setMessage(Message)}, fill in the addressing headers correctly, and this process
871 * requires the access to the request packet.
872 *
873 * <p>
874 * This method is useful when the caller needs to swap a response message completely to a new one.
875 *
876 * @see #createServerResponse(Message, AddressingVersion, SOAPVersion, String)
877 */
878 public void setResponseMessage(@NotNull Packet request, @Nullable Message responseMessage, @NotNull AddressingVersion addressingVersion, @NotNull SOAPVersion soapVersion, @NotNull String action) {
879 Packet temp = request.createServerResponse(responseMessage, addressingVersion, soapVersion, action);
880 setMessage(temp.getMessage());
881 }
882
883 private void populateAddressingHeaders(Packet responsePacket, AddressingVersion av, SOAPVersion sv, String action, boolean mustUnderstand) {
884 // populate WS-A headers only if WS-A is enabled
885 if (av == null) return;
886
887 // if one-way, then dont populate any WS-A headers
888 if (responsePacket.getMessage() == null)
889 return;
890
891 HeaderList hl = responsePacket.getMessage().getHeaders();
892
893 WsaPropertyBag wpb = getSatellite(WsaPropertyBag.class);
894
895 // wsa:To
896 WSEndpointReference replyTo = null;
897 if (wpb != null)
898 replyTo = wpb.getReplyToFromRequest();
899 if (replyTo == null)
900 replyTo = message.getHeaders().getReplyTo(av, sv);
901
902 // wsa:Action, add if the message doesn't already contain it,
903 // generally true for SEI case where there is SEIModel or WSDLModel
904 // false for Provider with no wsdl, Expects User to set the coresponding header on the Message.
905 if (responsePacket.getMessage().getHeaders().getAction(av, sv) == null) {
906 //wsa:Action header is not set in the message, so use the wsa:Action passed as the parameter.
907 hl.add(new StringHeader(av.actionTag, action, sv, mustUnderstand));
908 }
909
910 // wsa:MessageID
911 if (responsePacket.getMessage().getHeaders().get(av.messageIDTag, false) == null) {
912 // if header doesn't exist, method getID creates a new random id
913 String newID = Message.generateMessageID();
914 hl.add(new StringHeader(av.messageIDTag, newID));
915 }
916
917 // wsa:RelatesTo
918 String mid = null;
919 if (wpb != null)
920 mid = wpb.getMessageID();
921 if (mid == null)
922 mid = message.getHeaders().getMessageID(av, sv);
923 if (mid != null)
924 hl.add(new RelatesToHeader(av.relatesToTag, mid));
925
926
927 // populate reference parameters
928 WSEndpointReference refpEPR = null;
929 if (responsePacket.getMessage().isFault()) {
930 // choose FaultTo
931 if (wpb != null)
932 refpEPR = wpb.getFaultToFromRequest();
933 if (refpEPR == null)
934 refpEPR = message.getHeaders().getFaultTo(av, sv);
935 // if FaultTo is null, then use ReplyTo
936 if (refpEPR == null)
937 refpEPR = replyTo;
938 } else {
939 // choose ReplyTo
940 refpEPR = replyTo;
941 }
942 if (refpEPR != null) {
943 hl.add(new StringHeader(av.toTag, refpEPR.getAddress()));
944 refpEPR.addReferenceParametersToList(hl);
945 }
946 }
947
948 private void populateAddressingHeaders(WSBinding binding, Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) {
949 AddressingVersion addressingVersion = binding.getAddressingVersion();
950
951 if (addressingVersion == null) return;
952
953 WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, seiModel, binding);
954 String action = responsePacket.message.isFault() ?
955 wsaHelper.getFaultAction(this, responsePacket) :
956 wsaHelper.getOutputAction(this);
957 if (action == null) {
958 LOGGER.info("WSA headers are not added as value for wsa:Action cannot be resolved for this message");
959 return;
960 }
961 populateAddressingHeaders(responsePacket, addressingVersion, binding.getSOAPVersion(), action, addressingVersion.isRequired(binding));
962 }
963
964 public String toShortString() {
965 return super.toString();
966 }
967
968 // For use only in a debugger
969 public String toString() {
970 StringBuilder buf = new StringBuilder();
971 buf.append(super.toString());
972 String content;
973 try {
974 if (message != null) {
975 ByteArrayOutputStream baos = new ByteArrayOutputStream();
976 XMLStreamWriter xmlWriter = XMLStreamWriterFactory.create(baos, "UTF-8");
977 message.copy().writeTo(xmlWriter);
978 xmlWriter.flush();
979 xmlWriter.close();
980 baos.flush();
981 XMLStreamWriterFactory.recycle(xmlWriter);
982
983 byte[] bytes = baos.toByteArray();
984 //message = Messages.create(XMLStreamReaderFactory.create(null, new ByteArrayInputStream(bytes), "UTF-8", true));
985 content = new String(bytes, "UTF-8");
986 } else {
987 content = "<none>";
988 }
989 } catch (Throwable t) {
990 throw new WebServiceException(t);
991 }
992 buf.append(" Content: ").append(content);
993 return buf.toString();
994 }
995
996 // completes TypedMap
997 private static final PropertyMap model;
998
999 static {
1000 model = parse(Packet.class);
1001 }
1002
1003 protected PropertyMap getPropertyMap() {
1004 return model;
1005 }
1006
1007 private static final Logger LOGGER = Logger.getLogger(Packet.class.getName());
1008
1009 public SOAPMessage getSOAPMessage() throws SOAPException {
1010 return (message != null) ? message.readAsSOAPMessage() : null;
1011 }
1012
1013 Codec codec = null;
1014 Codec getCodec() {
1015 if (codec != null) return codec;
1016 if (endpoint != null) {
1017 codec = endpoint.createCodec();
1018 }
1019 WSBinding wsb = getBinding();
1020 if (wsb != null) {
1021 codec = wsb.getBindingId().createEncoder(wsb);
1022 }
1023 return codec;
1024 }
1025
1026
1027 public ContentType writeTo( OutputStream out ) throws IOException {
1028 return getCodec().encode(this, out);
1029 }
1030
1031 public ContentType writeTo( WritableByteChannel buffer ) {
1032 return getCodec().encode(this, buffer);
1033 }
1034 }
|
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>
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.
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
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.)
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.
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}).
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 }
1427 }
1428 return false;
1429 }
1430
1431 private boolean isMtomContentType() {
1432 return (getInternalContentType() != null) &&
1433 (getInternalContentType().getContentType().contains("application/xop+xml"));
1434 }
1435
1436 /**
1437 * @deprecated
1438 */
1439 public void addSatellite(@NotNull com.sun.xml.internal.ws.api.PropertySet satellite) {
1440 super.addSatellite(satellite);
1441 }
1442
1443 /**
1444 * @deprecated
1445 */
1446 public void addSatellite(@NotNull Class keyClass, @NotNull com.sun.xml.internal.ws.api.PropertySet satellite) {
1447 super.addSatellite(keyClass, satellite);
1448 }
1449
1450 /**
1451 * @deprecated
1452 */
1453 public void copySatelliteInto(@NotNull com.sun.xml.internal.ws.api.DistributedPropertySet r) {
1454 super.copySatelliteInto(r);
1455 }
1456
1457 /**
1458 * @deprecated
1459 */
1460 public void removeSatellite(com.sun.xml.internal.ws.api.PropertySet satellite) {
1461 super.removeSatellite(satellite);
1462 }
1463
1464 /**
1465 * This is propogated from SOAPBindingCodec and will affect isMtomAcceptable and isFastInfosetAcceptable
1466 */
1467 private boolean isFastInfosetDisabled;
1468
1469 public void setFastInfosetDisabled(boolean b) {
1470 isFastInfosetDisabled = b;
1471 }
1472 }
|