001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.xml.ws.api.message;
037:
038: import com.sun.istack.NotNull;
039: import com.sun.istack.Nullable;
040: import com.sun.xml.bind.marshaller.SAX2DOMEx;
041: import com.sun.xml.ws.addressing.WsaTubeHelper;
042: import com.sun.xml.ws.addressing.model.InvalidMapException;
043: import com.sun.xml.ws.api.DistributedPropertySet;
044: import com.sun.xml.ws.api.EndpointAddress;
045: import com.sun.xml.ws.api.PropertySet;
046: import com.sun.xml.ws.api.SOAPVersion;
047: import com.sun.xml.ws.api.WSBinding;
048: import com.sun.xml.ws.api.addressing.AddressingVersion;
049: import com.sun.xml.ws.api.addressing.WSEndpointReference;
050: import com.sun.xml.ws.api.model.SEIModel;
051: import com.sun.xml.ws.api.model.wsdl.WSDLOperation;
052: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
053: import com.sun.xml.ws.api.pipe.Tube;
054: import com.sun.xml.ws.api.server.TransportBackChannel;
055: import com.sun.xml.ws.api.server.WSEndpoint;
056: import com.sun.xml.ws.api.server.WebServiceContextDelegate;
057: import com.sun.xml.ws.client.BindingProviderProperties;
058: import com.sun.xml.ws.client.ContentNegotiation;
059: import com.sun.xml.ws.client.HandlerConfiguration;
060: import com.sun.xml.ws.client.ResponseContext;
061: import com.sun.xml.ws.developer.JAXWSProperties;
062: import com.sun.xml.ws.message.RelatesToHeader;
063: import com.sun.xml.ws.message.StringHeader;
064: import com.sun.xml.ws.util.DOMUtil;
065: import com.sun.xml.ws.util.xml.XmlUtil;
066: import org.w3c.dom.Document;
067: import org.w3c.dom.Element;
068: import org.xml.sax.SAXException;
069:
070: import javax.xml.soap.SOAPMessage;
071: import javax.xml.ws.BindingProvider;
072: import javax.xml.ws.Dispatch;
073: import javax.xml.ws.WebServiceContext;
074: import javax.xml.ws.WebServiceException;
075: import javax.xml.ws.handler.LogicalMessageContext;
076: import javax.xml.ws.handler.MessageContext;
077: import javax.xml.ws.handler.soap.SOAPMessageContext;
078: import java.util.ArrayList;
079: import java.util.Collections;
080: import java.util.HashMap;
081: import java.util.HashSet;
082: import java.util.List;
083: import java.util.Map;
084: import java.util.Set;
085:
086: /**
087: * Represents a container of a {@link Message}.
088: *
089: * <h2>What is a {@link Packet}?</h2>
090: * <p>
091: * A packet can be thought of as a frame/envelope/package that wraps
092: * a {@link Message}. A packet keeps track of optional metadata (properties)
093: * about a {@link Message} that doesn't go across the wire.
094: * This roughly corresponds to {@link MessageContext} in the JAX-WS API.
095: *
096: * <p>
097: * Usually a packet contains a {@link Message} in it, but sometimes
098: * (such as for a reply of an one-way operation), a packet may
099: * float around without a {@link Message} in it.
100: *
101: *
102: * <a name="properties"></a>
103: * <h2>Properties</h2>
104: * <p>
105: * Information frequently used inside the JAX-WS RI
106: * is stored in the strongly-typed fields. Other information is stored
107: * in terms of a generic {@link Map} (see
108: * {@link #invocationProperties}.)
109: *
110: * <p>
111: * Some properties need to be retained between request and response,
112: * some don't. For strongly typed fields, this characteristic is
113: * statically known for each of them, and propagation happens accordingly.
114: * For generic information stored in {@link Map}, {@link #invocationProperties}
115: * stores per-invocation scope information (which carries over to
116: * the response.)
117: *
118: * <p>
119: * This object is used as the backing store of {@link MessageContext}, and
120: * {@link LogicalMessageContext} and {@link SOAPMessageContext} will
121: * be delegating to this object for storing/retrieving values.
122: *
123: *
124: * <h3>Relationship to request/response context</h3>
125: * <p>
126: * {@link BindingProvider#getRequestContext() Request context} is used to
127: * seed the initial values of {@link Packet}.
128: * Some of those values go to strongly-typed fields, and others go to
129: * {@link #invocationProperties}, as they need to be retained in the reply message.
130: *
131: * <p>
132: * Similarly, {@link BindingProvider#getResponseContext() response context}
133: * is constructed from {@link Packet} (or rather it's just a view of {@link Packet}.)
134: * by using properties from {@link #invocationProperties},
135: * modulo properties named explicitly in {@link #getHandlerScopePropertyNames(boolean)}.
136: * IOW, properties added to {@link #invocationProperties}
137: * are exposed to the response context by default.
138: *
139: *
140: *
141: * <h3>TODO</h3>
142: * <ol>
143: * <li>this class needs to be cloneable since Message is copiable.
144: * <li>The three live views aren't implemented correctly. It will be
145: * more work to do so, although I'm sure it's possible.
146: * <li>{@link Property} annotation is to make it easy
147: * for {@link MessageContext} to export properties on this object,
148: * but it probably needs some clean up.
149: * </ol>
150: *
151: * @author Kohsuke Kawaguchi
152: */
153: public final class Packet extends DistributedPropertySet {
154:
155: /**
156: * Creates a {@link Packet} that wraps a given {@link Message}.
157: *
158: * <p>
159: * This method should be only used to create a fresh {@link Packet}.
160: * To create a {@link Packet} for a reply, use {@link #createResponse(Message)}.
161: *
162: * @param request
163: * The request {@link Message}. Can be null.
164: */
165: public Packet(Message request) {
166: this ();
167: this .message = request;
168: }
169:
170: /**
171: * Creates an empty {@link Packet} that doesn't have any {@link Message}.
172: */
173: public Packet() {
174: this .invocationProperties = new HashMap<String, Object>();
175: }
176:
177: /**
178: * Used by {@link #createResponse(Message)}.
179: */
180: private Packet(Packet that) {
181: that.copySatelliteInto(this );
182: this .handlerConfig = that.handlerConfig;
183: this .invocationProperties = that.invocationProperties;
184: this .handlerScopePropertyNames = that.handlerScopePropertyNames;
185: this .contentNegotiation = that.contentNegotiation;
186: this .wasTransportSecure = that.wasTransportSecure;
187: // copy other properties that need to be copied. is there any?
188: }
189:
190: private Message message;
191:
192: /**
193: * Gets the last {@link Message} set through {@link #setMessage(Message)}.
194: *
195: * @return
196: * may null. See the class javadoc for when it's null.
197: */
198: public Message getMessage() {
199: return message;
200: }
201:
202: /**
203: * Sets a {@link Message} to this packet.
204: *
205: * @param message
206: * Can be null.
207: */
208: public void setMessage(Message message) {
209: this .message = message;
210: }
211:
212: /**
213: * True if this message came from a transport (IOW inbound),
214: * and in paricular from a "secure" transport. A transport
215: * needs to set this flag appropriately.
216: *
217: * <p>
218: * This is a requirement from the security team.
219: */
220: // TODO: expose this as a property
221: public boolean wasTransportSecure;
222:
223: /**
224: * Inbound transport headers are captured in a transport neutral way.
225: * Transports are expected to fill this data after creating a Packet.
226: * <p>
227: * {@link SOAPMessage#getMimeHeaders()} would return these headers.
228: *
229: */
230: public static final String INBOUND_TRANSPORT_HEADERS = "com.sun.xml.ws.api.message.packet.inbound.transport.headers";
231:
232: /**
233: * Outbound transport headers are captured in a transport neutral way.
234: *
235: * <p>
236: * Transports may choose to ignore certain headers that interfere with
237: * its correct operation, such as
238: * <tt>Content-Type</tt> and <tt>Content-Length</tt>.
239: */
240: public static final String OUTBOUND_TRANSPORT_HEADERS = "com.sun.xml.ws.api.message.packet.outbound.transport.headers";
241:
242: /**
243: * This property holds the snapshot of HandlerConfiguration
244: * at the time of invocation.
245: * This property is used by MUPipe and HandlerPipe implementations.
246: */
247: @Property(BindingProviderProperties.JAXWS_HANDLER_CONFIG)
248: public HandlerConfiguration handlerConfig;
249:
250: /**
251: * If a message originates from a proxy stub that implements
252: * a port interface, this field is set to point to that object.
253: *
254: * TODO: who's using this property?
255: */
256: @Property(BindingProviderProperties.JAXWS_CLIENT_HANDLE_PROPERTY)
257: public BindingProvider proxy;
258:
259: /**
260: * The endpoint address to which this message is sent to.
261: *
262: * <p>
263: * The JAX-WS spec allows this to be changed for each message,
264: * so it's designed to be a property.
265: *
266: * <p>
267: * Must not be null for a request message on the client. Otherwise
268: * it's null.
269: */
270: public EndpointAddress endpointAddress;
271:
272: /**
273: * @deprecated
274: * The programatic acccess should be done via
275: * {@link #endpointAddress}. This is for JAX-WS client applications
276: * that access this property via {@link BindingProvider#ENDPOINT_ADDRESS_PROPERTY}.
277: */
278: @Property(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)
279: public String getEndPointAddressString() {
280: if (endpointAddress == null)
281: return null;
282: else
283: return endpointAddress.toString();
284: }
285:
286: public void setEndPointAddressString(String s) {
287: if (s == null)
288: this .endpointAddress = null;
289: else
290: this .endpointAddress = EndpointAddress.create(s);
291: }
292:
293: /**
294: * The value of {@link ContentNegotiation#PROPERTY}
295: * property.
296: *
297: * This property is used only on the client side.
298: */
299: public ContentNegotiation contentNegotiation;
300:
301: @Property(ContentNegotiation.PROPERTY)
302: public String getContentNegotiationString() {
303: return (contentNegotiation != null) ? contentNegotiation
304: .toString() : null;
305: }
306:
307: public void setContentNegotiationString(String s) {
308: if (s == null)
309: contentNegotiation = null;
310: else {
311: try {
312: contentNegotiation = ContentNegotiation.valueOf(s);
313: } catch (IllegalArgumentException e) {
314: // If the value is not recognized default to none
315: contentNegotiation = ContentNegotiation.none;
316: }
317: }
318: }
319:
320: /**
321: * Gives a list of Reference Parameters in the Message
322: * <p>
323: * Headers which have attribute wsa:IsReferenceParameter="true"
324: * This is not cached as one may reset the Message.
325: *<p>
326: */
327: @Property(MessageContext.REFERENCE_PARAMETERS)
328: public @NotNull
329: List<Element> getReferenceParameters() {
330: List<Element> refParams = new ArrayList<Element>();
331: HeaderList hl = message.getHeaders();
332: for (Header h : hl) {
333: String attr = h.getAttribute(AddressingVersion.W3C.nsUri,
334: "IsReferenceParameter");
335: if (attr != null
336: && (attr.equals("true") || attr.equals("1"))) {
337: Document d = DOMUtil.createDom();
338: SAX2DOMEx s2d = new SAX2DOMEx(d);
339: try {
340: h.writeTo(s2d, XmlUtil.DRACONIAN_ERROR_HANDLER);
341: refParams.add((Element) d.getLastChild());
342: } catch (SAXException e) {
343: throw new WebServiceException(e);
344: }
345: /*
346: DOMResult result = new DOMResult(d);
347: XMLDOMWriterImpl domwriter = new XMLDOMWriterImpl(result);
348: try {
349: h.writeTo(domwriter);
350: refParams.add((Element) result.getNode().getLastChild());
351: } catch (XMLStreamException e) {
352: throw new WebServiceException(e);
353: }
354: */
355: }
356: }
357: return refParams;
358: }
359:
360: /**
361: * @deprecated
362: * This method is for exposing header list through {@link PropertySet#get(Object)},
363: * for user applications, and should never be invoked directly from within the JAX-WS RI.
364: */
365: @Property(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY)
366: /*package*/HeaderList getHeaderList() {
367: if (message == null)
368: return null;
369: return message.getHeaders();
370: }
371:
372: /**
373: * The list of MIME types that are acceptable to a receiver
374: * of an outbound message.
375: *
376: * This property is used only on the server side.
377: *
378: * <p>The representation shall be that specified by the HTTP Accept
379: * request-header field.
380: *
381: * <p>The list of content types will be obtained from the transport
382: * meta-data of a inbound message in a request/response message exchange.
383: * Hence this property will be set by the service-side transport pipe.
384: *
385: */
386: public String acceptableMimeTypes;
387:
388: /**
389: * When non-null, this object is consulted to
390: * implement {@link WebServiceContext} methods
391: * exposed to the user application.
392: *
393: * Used only on the server side.
394: *
395: * <p>
396: * This property is set from the parameter
397: * of {@link WSEndpoint.PipeHead#process}.
398: */
399: public WebServiceContextDelegate webServiceContextDelegate;
400:
401: /**
402: * Used only on the server side so that the transport
403: * can close the connection early.
404: *
405: * <p>
406: * This field can be null. While a message is being processed,
407: * this field can be set explicitly to null, to prevent
408: * future pipes from closing a transport.
409: *
410: * <p>
411: * This property is set from the parameter
412: * of {@link WSEndpoint.PipeHead#process}.
413: */
414: public @Nullable
415: TransportBackChannel transportBackChannel;
416:
417: /**
418: * The governing {@link WSEndpoint} in which this message is floating.
419: *
420: * <p>
421: * This property is set if and only if this is on the server side.
422: */
423: @Property(JAXWSProperties.WSENDPOINT)
424: public WSEndpoint endpoint;
425:
426: /**
427: * The value of the SOAPAction header associated with the message.
428: *
429: * <p>
430: * For outgoing messages, the transport may sends out this value.
431: * If this field is null, the transport may choose to send <tt>""</tt>
432: * (quoted empty string.)
433: *
434: * For incoming messages, the transport will set this field.
435: * If the incoming message did not contain the SOAPAction header,
436: * the transport sets this field to null.
437: *
438: * <p>
439: * If the value is non-null, it must be always in the quoted form.
440: * The value can be null.
441: *
442: * <p>
443: * Note that the way the transport sends this value out depends on
444: * transport and SOAP version.
445: *
446: * For HTTP transport and SOAP 1.1, BP requires that SOAPAction
447: * header is present (See {@BP R2744} and {@BP R2745}.) For SOAP 1.2,
448: * this is moved to the parameter of the "application/soap+xml".
449: */
450: @Property(BindingProvider.SOAPACTION_URI_PROPERTY)
451: public String soapAction;
452:
453: /**
454: * A hint indicating that whether a transport should expect
455: * a reply back from the server.
456: *
457: * <p>
458: * This property is used on the client-side for
459: * outbound messages, so that a pipeline
460: * can communicate to the terminal (or intermediate) {@link Tube}s
461: * about this knowledge.
462: *
463: * <p>
464: * This property <b>MUST NOT</b> be used by 2-way transports
465: * that have the transport back channel. Those transports
466: * must always check a reply coming through the transport back
467: * channel regardless of this value, and act accordingly.
468: * (This is because the expectation of the client and
469: * that of the server can be different, for example because
470: * of a bug in user's configuration.)
471: *
472: * <p>
473: * This property is for one-way transports, and more
474: * specifically for the coordinator that correlates sent requests
475: * and incoming replies, to decide whether to block
476: * until a response is received.
477: *
478: * <p>
479: * Also note that this property is related to
480: * {@link WSDLOperation#isOneWay()} but not the same thing.
481: * In fact in general, they are completely orthogonal.
482: *
483: * For example, the calling application can choose to invoke
484: * {@link Dispatch#invoke(Object)} or {@link Dispatch#invokeOneWay(Object)}
485: * with an operation (which determines the value of this property),
486: * regardless of whether WSDL actually says it's one way or not.
487: * So these two booleans can take any combinations.
488: *
489: *
490: * <p>
491: * When this property is {@link Boolean#TRUE}, it means that
492: * the pipeline does not expect a reply from a server (and therefore
493: * the correlator should not block for a reply message
494: * -- if such a reply does arrive, it can be just ignored.)
495: *
496: * <p>
497: * When this property is {@link Boolean#FALSE}, it means that
498: * the pipeline expects a reply from a server (and therefore
499: * the correlator should block to see if a reply message is received,
500: *
501: * <p>
502: * This property is always set to {@link Boolean#TRUE} or
503: * {@link Boolean#FALSE} when used on the request message
504: * on the client side.
505: * No other {@link Boolean} instances are allowed.
506: * <p>
507: *
508: * In all other situations, this property is null.
509: *
510: */
511: @Property(BindingProviderProperties.ONE_WAY_OPERATION)
512: public Boolean expectReply;
513:
514: /**
515: * This property will be removed in a near future.
516: *
517: * <p>
518: * A part of what this flag represented moved to
519: * {@link #expectReply} and the other part was moved
520: * to {@link Message#isOneWay(WSDLPort)}. Please update
521: * your code soon, or risk breaking your build!!
522: */
523: @Deprecated
524: public Boolean isOneWay;
525:
526: /**
527: * Lazily created set of handler-scope property names.
528: *
529: * <p>
530: * We expect that this is only used when handlers are present
531: * and they explicitly set some handler-scope values.
532: *
533: * @see #getHandlerScopePropertyNames(boolean)
534: */
535: private Set<String> handlerScopePropertyNames;
536:
537: /**
538: * Bag to capture properties that are available for the whole
539: * message invocation (namely on both requests and responses.)
540: *
541: * <p>
542: * These properties are copied from a request to a response.
543: * This is where we keep properties that are set by handlers.
544: *
545: * <p>
546: * See <a href="#properties">class javadoc</a> for more discussion.
547: *
548: * @see #getHandlerScopePropertyNames(boolean)
549: */
550: public final Map<String, Object> invocationProperties;
551:
552: /**
553: * Gets a {@link Set} that stores handler-scope properties.
554: *
555: * <p>
556: * These properties will not be exposed to the response context.
557: * Consequently, if a {@link Tube} wishes to hide a property
558: * to {@link ResponseContext}, it needs to add the property name
559: * to this set.
560: *
561: * @param readOnly
562: * Return true if the caller only intends to read the value of this set.
563: * Internally, the {@link Set} is allocated lazily, and this flag helps
564: * optimizing the strategy.
565: *
566: * @return
567: * always non-null, possibly empty set that stores property names.
568: */
569: public final Set<String> getHandlerScopePropertyNames(
570: boolean readOnly) {
571: Set<String> o = this .handlerScopePropertyNames;
572: if (o == null) {
573: if (readOnly)
574: return Collections.emptySet();
575: o = new HashSet<String>();
576: this .handlerScopePropertyNames = o;
577: }
578: return o;
579: }
580:
581: /**
582: * This method no longer works.
583: *
584: * @deprecated
585: * Use {@link #getHandlerScopePropertyNames(boolean)}.
586: * To be removed once Tango components are updated.
587: */
588: public final Set<String> getApplicationScopePropertyNames(
589: boolean readOnly) {
590: assert false;
591: return new HashSet<String>();
592: }
593:
594: /**
595: * Creates a response {@link Packet} from a request packet ({@code this}).
596: *
597: * <p>
598: * When a {@link Packet} for a reply is created, some properties need to be
599: * copied over from a request to a response, and this method handles it correctly.
600: *
601: * @deprecated
602: * Use createClientResponse(Message) for client side and
603: * createServerResponse(Message, String) for server side response
604: * creation.
605: *
606: * @param msg
607: * The {@link Message} that represents a reply. Can be null.
608: */
609: @Deprecated
610: public Packet createResponse(Message msg) {
611: Packet response = new Packet(this );
612: response.setMessage(msg);
613: return response;
614: }
615:
616: /**
617: * Creates a response {@link Packet} from a request packet ({@code this}).
618: *
619: * <p>
620: * When a {@link Packet} for a reply is created, some properties need to be
621: * copied over from a request to a response, and this method handles it correctly.
622: *
623: * @param msg
624: * The {@link Message} that represents a reply. Can be null.
625: */
626: public Packet createClientResponse(Message msg) {
627: Packet response = new Packet(this );
628: response.setMessage(msg);
629: return response;
630: }
631:
632: /**
633: * Creates a server-side response {@link Packet} from a request
634: * packet ({@code this}). If WS-Addressing is enabled, a default Action
635: * Message Addressing Property is obtained using <code>wsdlPort</code> {@link WSDLPort}
636: * and <code>binding</code> {@link WSBinding}.
637: * <p><p>
638: * This method should be called to create application response messages
639: * since they are associated with a {@link WSBinding} and {@link WSDLPort}.
640: * For creating protocol messages that require a non-default Action, use
641: * {@link #createServerResponse(Message, com.sun.xml.ws.api.addressing.AddressingVersion, com.sun.xml.ws.api.SOAPVersion, String)}.
642: *
643: * @param responseMessage The {@link Message} that represents a reply. Can be null.
644: * @param wsdlPort The response WSDL port.
645: * @param binding The response Binding. Cannot be null.
646: * @return response packet
647: */
648: public Packet createServerResponse(@Nullable
649: Message responseMessage, @Nullable
650: WSDLPort wsdlPort, @Nullable
651: SEIModel seiModel, @NotNull
652: WSBinding binding) {
653: Packet r = createClientResponse(responseMessage);
654:
655: AddressingVersion av = binding.getAddressingVersion();
656: // populate WS-A headers only if WS-A is enabled
657: if (av == null)
658: return r;
659: //populate WS-A headers only if the request has addressing headers
660: String inputAction = this .getMessage().getHeaders().getAction(
661: av, binding.getSOAPVersion());
662: if (inputAction == null) {
663: return r;
664: }
665: // if one-way, then dont populate any WS-A headers
666: if (responseMessage == null
667: || (wsdlPort != null && message.isOneWay(wsdlPort)))
668: return r;
669:
670: // otherwise populate WS-Addressing headers
671: populateAddressingHeaders(binding, r, wsdlPort, seiModel);
672: return r;
673: }
674:
675: /**
676: * Creates a server-side response {@link Packet} from a request
677: * packet ({@code this}). If WS-Addressing is enabled, <code>action</code>
678: * is used as Action Message Addressing Property.
679: * <p><p>
680: * This method should be called only for creating protocol response messages
681: * that require a particular value of Action since they are not associated
682: * with a {@link WSBinding} and {@link WSDLPort} but do know the {@link AddressingVersion}
683: * and {@link SOAPVersion}.
684: *
685: * @param responseMessage The {@link Message} that represents a reply. Can be null.
686: * @param addressingVersion The WS-Addressing version of the response message.
687: * @param soapVersion The SOAP version of the response message.
688: * @param action The response Action Message Addressing Property value.
689: * @return response packet
690: */
691: public Packet createServerResponse(@Nullable
692: Message responseMessage, @NotNull
693: AddressingVersion addressingVersion, @NotNull
694: SOAPVersion soapVersion, @NotNull
695: String action) {
696: Packet responsePacket = createClientResponse(responseMessage);
697:
698: // populate WS-A headers only if WS-A is enabled
699: if (addressingVersion == null)
700: return responsePacket;
701: //populate WS-A headers only if the request has addressing headers
702: String inputAction = this .getMessage().getHeaders().getAction(
703: addressingVersion, soapVersion);
704: if (inputAction == null) {
705: return responsePacket;
706: }
707:
708: populateAddressingHeaders(responsePacket, addressingVersion,
709: soapVersion, action);
710: return responsePacket;
711: }
712:
713: private void populateAddressingHeaders(Packet responsePacket,
714: AddressingVersion av, SOAPVersion sv, String action) {
715: // populate WS-A headers only if WS-A is enabled
716: if (av == null)
717: return;
718:
719: // if one-way, then dont populate any WS-A headers
720: if (responsePacket.getMessage() == null)
721: return;
722:
723: HeaderList hl = responsePacket.getMessage().getHeaders();
724:
725: // wsa:To
726: WSEndpointReference replyTo;
727: try {
728: replyTo = message.getHeaders().getReplyTo(av, sv);
729: if (replyTo != null)
730: hl
731: .add(new StringHeader(av.toTag, replyTo
732: .getAddress()));
733: } catch (InvalidMapException e) {
734: replyTo = null;
735: }
736:
737: // wsa:Action
738: hl.add(new StringHeader(av.actionTag, action));
739:
740: // wsa:MessageID
741: hl.add(new StringHeader(av.messageIDTag, responsePacket
742: .getMessage().getID(av, sv)));
743:
744: // wsa:RelatesTo
745: String mid = getMessage().getHeaders().getMessageID(av, sv);
746: if (mid != null)
747: hl.add(new RelatesToHeader(av.relatesToTag, mid));
748:
749: // populate reference parameters
750: WSEndpointReference refpEPR;
751: if (responsePacket.getMessage().isFault()) {
752: // choose FaultTo
753: refpEPR = message.getHeaders().getFaultTo(av, sv);
754:
755: // if FaultTo is null, then use ReplyTo
756: if (refpEPR == null)
757: refpEPR = replyTo;
758: } else {
759: // choose ReplyTo
760: refpEPR = replyTo;
761: }
762: if (refpEPR != null) {
763: refpEPR.addReferenceParameters(hl);
764: }
765: }
766:
767: private void populateAddressingHeaders(WSBinding binding,
768: Packet responsePacket, WSDLPort wsdlPort, SEIModel seiModel) {
769: AddressingVersion addressingVersion = binding
770: .getAddressingVersion();
771:
772: if (addressingVersion == null)
773: return;
774:
775: WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(
776: wsdlPort, seiModel, binding);
777: String action = responsePacket.message.isFault() ? wsaHelper
778: .getFaultAction(this , responsePacket) : wsaHelper
779: .getOutputAction(this );
780:
781: populateAddressingHeaders(responsePacket, addressingVersion,
782: binding.getSOAPVersion(), action);
783: }
784:
785: // completes TypedMap
786: private static final PropertyMap model;
787:
788: static {
789: model = parse(Packet.class);
790: }
791:
792: protected PropertyMap getPropertyMap() {
793: return model;
794: }
795: }
|