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.ws.addressing.WsaTubeHelper;
041: import com.sun.xml.ws.api.SOAPVersion;
042: import com.sun.xml.ws.api.WSBinding;
043: import com.sun.xml.ws.api.addressing.AddressingVersion;
044: import com.sun.xml.ws.api.addressing.OneWayFeature;
045: import com.sun.xml.ws.api.addressing.WSEndpointReference;
046: import com.sun.xml.ws.api.model.wsdl.WSDLBoundOperation;
047: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
048: import com.sun.xml.ws.api.pipe.Pipe;
049: import com.sun.xml.ws.api.pipe.Codec;
050: import com.sun.xml.ws.message.RelatesToHeader;
051: import com.sun.xml.ws.message.StringHeader;
052: import com.sun.xml.ws.protocol.soap.ClientMUTube;
053: import com.sun.xml.ws.protocol.soap.ServerMUTube;
054: import com.sun.xml.ws.resources.AddressingMessages;
055: import com.sun.xml.ws.resources.ClientMessages;
056:
057: import javax.xml.namespace.QName;
058: import javax.xml.stream.XMLStreamException;
059: import javax.xml.ws.WebServiceException;
060: import java.util.ArrayList;
061: import java.util.BitSet;
062: import java.util.Collection;
063: import java.util.Iterator;
064: import java.util.NoSuchElementException;
065: import java.util.Set;
066:
067: /**
068: * A list of {@link Header}s on a {@link Message}.
069: *
070: * <p>
071: * This list can be modified to add headers
072: * from outside a {@link Message}, this is necessary
073: * since intermediate processing layers often need to
074: * put additional headers.
075: *
076: * <p>
077: * Following the SOAP convention, the order among headers
078: * are not significant. However, {@link Codec}s are
079: * expected to preserve the order of headers in the input
080: * message as much as possible.
081: *
082: *
083: * <a name="MU"></a>
084: * <h3>MustUnderstand Processing</h3>
085: * <p>
086: * To perform SOAP mustUnderstang processing correctly, we need to keep
087: * track of headers that are understood and headers that are not.
088: * This is a collaborative process among {@link Pipe}s, thus it's something
089: * a {@link Pipe} author needs to keep in mind.
090: *
091: * <p>
092: * Specifically, when a {@link Pipe} sees a header and processes it
093: * (that is, if it did enough computing with the header to claim that
094: * the header is understood), then it should mark the corresponding
095: * header as "understood". For example, when a pipe that handles JAX-WSA
096: * examins the <wsa:To> header, it can claim that it understood the header.
097: * But for example, if a pipe that does the signature verification checks
098: * <wsa:To> for a signature, that would not be considered as "understood".
099: *
100: * <p>
101: * There are two ways to mark a header as understood:
102: *
103: * <ol>
104: * <li>Use one of the <tt>getXXX</tt> methods that take a
105: * boolean <tt>markAsUnderstood</tt> parameter.
106: * Most often, a {@link Pipe} knows it's going to understand a header
107: * as long as it's present, so this is the easiest and thus the preferred way.
108: *
109: * For example, if JAX-WSA looks for <wsa:To>, then it can set
110: * <tt>markAsUnderstand</tt> to true, to do the obtaining of a header
111: * and marking at the same time.
112: *
113: * <li>Call {@link #understood(int)}.
114: * If under a rare circumstance, a pipe cannot determine whether
115: * it can understand it or not when you are fetching a header, then
116: * you can use this method afterward to mark it as understood.
117: * </ol>
118: *
119: * <p>
120: * Intuitively speaking, at the end of the day, if a header is not
121: * understood but {@link Header#isIgnorable(SOAPVersion, Set)} is false, a bad thing
122: * will happen. The actual implementation of the checking is more complicated,
123: * for that see {@link ClientMUTube}/{@link ServerMUTube}.
124: *
125: * @see Message#getHeaders()
126: */
127: public final class HeaderList extends ArrayList<Header> {
128:
129: /**
130: * Bit set to keep track of which headers are understood.
131: * <p>
132: * The first 32 headers use this field, and the rest will use
133: * {@link #moreUnderstoodBits}. The expectation is that
134: * most of the time a SOAP message will only have up to 32 headers,
135: * so we can avoid allocating separate objects for {@link BitSet}.
136: */
137: private int understoodBits;
138: /**
139: * If there are more than 32 headers, we use this {@link BitSet}
140: * to keep track of whether those headers are understood.
141: * Lazily allocated.
142: */
143: private BitSet moreUnderstoodBits = null;
144:
145: private String to = null;
146: private String action = null;
147: private WSEndpointReference replyTo = null;
148: private WSEndpointReference faultTo = null;
149: private String messageId;
150:
151: /**
152: * Creates an empty {@link HeaderList}.
153: */
154: public HeaderList() {
155: }
156:
157: /**
158: * Copy constructor.
159: */
160: public HeaderList(HeaderList that) {
161: super (that);
162: this .understoodBits = that.understoodBits;
163: if (that.moreUnderstoodBits != null)
164: this .moreUnderstoodBits = (BitSet) that.moreUnderstoodBits
165: .clone();
166: this .to = that.to;
167: this .action = that.action;
168: this .replyTo = that.replyTo;
169: this .faultTo = that.faultTo;
170: this .messageId = that.messageId;
171: }
172:
173: /**
174: * The number of total headers.
175: */
176: public int size() {
177: return super .size();
178: }
179:
180: /**
181: * Adds all the headers.
182: */
183: public void addAll(Header... headers) {
184: for (Header header : headers)
185: add(header);
186: }
187:
188: /**
189: * Gets the {@link Header} at the specified index.
190: *
191: * <p>
192: * This method does not mark the returned {@link Header} as understood.
193: *
194: * @see #understood(int)
195: */
196: public Header get(int index) {
197: return super .get(index);
198: }
199:
200: /**
201: * Marks the {@link Header} at the specified index as
202: * <a href="#MU">"understood"</a>.
203: */
204: public void understood(int index) {
205: assert index < size(); // check that index is in range
206: if (index < 32)
207: understoodBits |= 1 << index;
208: else {
209: if (moreUnderstoodBits == null)
210: moreUnderstoodBits = new BitSet();
211: moreUnderstoodBits.set(index - 32);
212: }
213: }
214:
215: /**
216: * Returns true if a {@link Header} at the given index
217: * was <a href="#MU">"understood"</a>.
218: */
219: public boolean isUnderstood(int index) {
220: assert index < size(); // check that index is in range
221: if (index < 32)
222: return understoodBits == (understoodBits | (1 << index));
223: else {
224: if (moreUnderstoodBits == null)
225: return false;
226: return moreUnderstoodBits.get(index - 32);
227: }
228: }
229:
230: /**
231: * Marks the specified {@link Header} as <a href="#MU">"understood"</a>.
232: *
233: * @deprecated
234: * By the deifnition of {@link ArrayList}, this operation requires
235: * O(n) search of the array, and thus inherently inefficient.
236: *
237: * Because of this, if you are developing a {@link Pipe} for
238: * a performance sensitive environment, do not use this method.
239: *
240: * @throws IllegalArgumentException
241: * if the given header is not {@link #contains(Object) contained}
242: * in this header.
243: */
244: public void understood(@NotNull
245: Header header) {
246: int sz = size();
247: for (int i = 0; i < sz; i++) {
248: if (get(i) == header) {
249: understood(i);
250: return;
251: }
252: }
253: throw new IllegalArgumentException();
254: }
255:
256: /**
257: * Gets the first {@link Header} of the specified name.
258: *
259: * @param markAsUnderstood
260: * If this parameter is true, the returned header will
261: * be marked as <a href="#MU">"understood"</a>.
262: * @return null if not found.
263: */
264: public @Nullable
265: Header get(@NotNull
266: String nsUri, @NotNull
267: String localName, boolean markAsUnderstood) {
268: int len = size();
269: for (int i = 0; i < len; i++) {
270: Header h = get(i);
271: if (h.getLocalPart().equals(localName)
272: && h.getNamespaceURI().equals(nsUri)) {
273: if (markAsUnderstood)
274: understood(i);
275: return h;
276: }
277: }
278: return null;
279: }
280:
281: /**
282: * @deprecated
283: * Use {@link #get(String, String, boolean)}
284: */
285: public Header get(String nsUri, String localName) {
286: return get(nsUri, localName, true);
287: }
288:
289: /**
290: * Gets the first {@link Header} of the specified name.
291: *
292: * @param markAsUnderstood
293: * If this parameter is true, the returned header will
294: * be marked as <a href="#MU">"understood"</a>.
295: * @return null
296: * if not found.
297: */
298: public @Nullable
299: Header get(@NotNull
300: QName name, boolean markAsUnderstood) {
301: return get(name.getNamespaceURI(), name.getLocalPart(),
302: markAsUnderstood);
303: }
304:
305: /**
306: * @deprecated
307: * Use {@link #get(QName)}
308: */
309: public @Nullable
310: Header get(@NotNull
311: QName name) {
312: return get(name, true);
313: }
314:
315: /**
316: * @deprecated
317: * Use {@link #getHeaders(String, String, boolean)}
318: */
319: public Iterator<Header> getHeaders(final String nsUri,
320: final String localName) {
321: return getHeaders(nsUri, localName, true);
322: }
323:
324: /**
325: * Gets all the {@link Header}s of the specified name,
326: * including duplicates (if any.)
327: *
328: * @param markAsUnderstood
329: * If this parameter is true, the returned headers will
330: * be marked as <a href="#MU">"understood"</a> when they are returned
331: * from {@link Iterator#next()}.
332: * @return empty iterator if not found.
333: */
334: public @NotNull
335: Iterator<Header> getHeaders(@NotNull
336: final String nsUri, @NotNull
337: final String localName, final boolean markAsUnderstood) {
338: return new Iterator<Header>() {
339: int idx = 0;
340: Header next;
341:
342: public boolean hasNext() {
343: if (next == null)
344: fetch();
345: return next != null;
346: }
347:
348: public Header next() {
349: if (next == null) {
350: fetch();
351: if (next == null)
352: throw new NoSuchElementException();
353: }
354:
355: if (markAsUnderstood) {
356: assert get(idx - 1) == next;
357: understood(idx - 1);
358: }
359:
360: Header r = next;
361: next = null;
362: return r;
363: }
364:
365: private void fetch() {
366: while (idx < size()) {
367: Header h = get(idx++);
368: if (h.getLocalPart().equals(localName)
369: && h.getNamespaceURI().equals(nsUri)) {
370: next = h;
371: break;
372: }
373: }
374: }
375:
376: public void remove() {
377: throw new UnsupportedOperationException();
378: }
379: };
380: }
381:
382: /**
383: * @see #getHeaders(String, String, boolean)
384: */
385: public @NotNull
386: Iterator<Header> getHeaders(@NotNull
387: QName headerName, final boolean markAsUnderstood) {
388: return getHeaders(headerName.getNamespaceURI(), headerName
389: .getLocalPart(), markAsUnderstood);
390: }
391:
392: /**
393: * @deprecated
394: * use {@link #getHeaders(String, boolean)}.
395: */
396: public @NotNull
397: Iterator<Header> getHeaders(@NotNull
398: final String nsUri) {
399: return getHeaders(nsUri, true);
400: }
401:
402: /**
403: * Gets an iteration of headers {@link Header} in the specified namespace,
404: * including duplicates (if any.)
405: *
406: * @param markAsUnderstood
407: * If this parameter is true, the returned headers will
408: * be marked as <a href="#MU">"understood"</a> when they are returned
409: * from {@link Iterator#next()}.
410: * @return
411: * empty iterator if not found.
412: */
413: public @NotNull
414: Iterator<Header> getHeaders(@NotNull
415: final String nsUri, final boolean markAsUnderstood) {
416: return new Iterator<Header>() {
417: int idx = 0;
418: Header next;
419:
420: public boolean hasNext() {
421: if (next == null)
422: fetch();
423: return next != null;
424: }
425:
426: public Header next() {
427: if (next == null) {
428: fetch();
429: if (next == null)
430: throw new NoSuchElementException();
431: }
432:
433: if (markAsUnderstood) {
434: assert get(idx - 1) == next;
435: understood(idx - 1);
436: }
437:
438: Header r = next;
439: next = null;
440: return r;
441: }
442:
443: private void fetch() {
444: while (idx < size()) {
445: Header h = get(idx++);
446: if (h.getNamespaceURI().equals(nsUri)) {
447: next = h;
448: break;
449: }
450: }
451: }
452:
453: public void remove() {
454: throw new UnsupportedOperationException();
455: }
456: };
457: }
458:
459: /**
460: * Gets the first {@link Header} of the specified name targeted at the
461: * current implicit role.
462: *
463: * @param name name of the header
464: * @param markUnderstood
465: * If this parameter is true, the returned headers will
466: * be marked as <a href="#MU">"understood"</a> when they are returned
467: * from {@link Iterator#next()}.
468: * @return null if header not found
469: */
470: private Header getFirstHeader(QName name, boolean markUnderstood,
471: SOAPVersion sv) {
472: if (sv == null)
473: throw new IllegalArgumentException(AddressingMessages
474: .NULL_SOAP_VERSION());
475:
476: Iterator<Header> iter = getHeaders(name.getNamespaceURI(), name
477: .getLocalPart(), markUnderstood);
478: while (iter.hasNext()) {
479: Header h = iter.next();
480: if (h.getRole(sv).equals(sv.implicitRole))
481: return h;
482: }
483:
484: return null;
485: }
486:
487: /**
488: * Returns the value of WS-Addressing <code>To</code> header. The <code>version</code>
489: * identifies the WS-Addressing version and the header returned is targeted at
490: * the current implicit role. Caches the value for subsequent invocation.
491: * Duplicate <code>To</code> headers are detected earlier.
492: *
493: * @param av WS-Addressing version
494: * @param sv SOAP version
495: * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
496: * @return Value of WS-Addressing To header, anonymous URI if no header is present
497: */
498: public String getTo(AddressingVersion av, SOAPVersion sv) {
499: if (to != null)
500: return to;
501: if (av == null)
502: throw new IllegalArgumentException(AddressingMessages
503: .NULL_ADDRESSING_VERSION());
504:
505: Header h = getFirstHeader(av.toTag, true, sv);
506: if (h != null) {
507: to = h.getStringContent();
508: } else {
509: to = av.anonymousUri;
510: }
511:
512: return to;
513: }
514:
515: /**
516: * Returns the value of WS-Addressing <code>Action</code> header. The <code>version</code>
517: * identifies the WS-Addressing version and the header returned is targeted at
518: * the current implicit role. Caches the value for subsequent invocation.
519: * Duplicate <code>Action</code> headers are detected earlier.
520: *
521: * @param av WS-Addressing version
522: * @param sv SOAP version
523: * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
524: * @return Value of WS-Addressing Action header, null if no header is present
525: */
526: public String getAction(@NotNull
527: AddressingVersion av, @NotNull
528: SOAPVersion sv) {
529: if (action != null)
530: return action;
531: if (av == null)
532: throw new IllegalArgumentException(AddressingMessages
533: .NULL_ADDRESSING_VERSION());
534:
535: Header h = getFirstHeader(av.actionTag, true, sv);
536: if (h != null) {
537: action = h.getStringContent();
538: }
539:
540: return action;
541: }
542:
543: /**
544: * Returns the value of WS-Addressing <code>ReplyTo</code> header. The <code>version</code>
545: * identifies the WS-Addressing version and the header returned is targeted at
546: * the current implicit role. Caches the value for subsequent invocation.
547: * Duplicate <code>ReplyTo</code> headers are detected earlier.
548: *
549: * @param av WS-Addressing version
550: * @param sv SOAP version
551: * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
552: * @return Value of WS-Addressing ReplyTo header, null if no header is present
553: */
554: public WSEndpointReference getReplyTo(@NotNull
555: AddressingVersion av, @NotNull
556: SOAPVersion sv) {
557: if (replyTo != null)
558: return replyTo;
559: if (av == null)
560: throw new IllegalArgumentException(AddressingMessages
561: .NULL_ADDRESSING_VERSION());
562:
563: Header h = getFirstHeader(av.replyToTag, true, sv);
564: if (h != null) {
565: try {
566: replyTo = h.readAsEPR(av);
567: } catch (XMLStreamException e) {
568: throw new WebServiceException(AddressingMessages
569: .REPLY_TO_CANNOT_PARSE(), e);
570: }
571: } else {
572: replyTo = av.anonymousEpr;
573: }
574:
575: return replyTo;
576: }
577:
578: /**
579: * Returns the value of WS-Addressing <code>FaultTo</code> header. The <code>version</code>
580: * identifies the WS-Addressing version and the header returned is targeted at
581: * the current implicit role. Caches the value for subsequent invocation.
582: * Duplicate <code>FaultTo</code> headers are detected earlier.
583: *
584: * @param av WS-Addressing version
585: * @param sv SOAP version
586: * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
587: * @return Value of WS-Addressing FaultTo header, null if no header is present
588: */
589: public WSEndpointReference getFaultTo(@NotNull
590: AddressingVersion av, @NotNull
591: SOAPVersion sv) {
592: if (faultTo != null)
593: return faultTo;
594:
595: if (av == null)
596: throw new IllegalArgumentException(AddressingMessages
597: .NULL_ADDRESSING_VERSION());
598:
599: Header h = getFirstHeader(av.faultToTag, true, sv);
600: if (h != null) {
601: try {
602: faultTo = h.readAsEPR(av);
603: } catch (XMLStreamException e) {
604: throw new WebServiceException(AddressingMessages
605: .FAULT_TO_CANNOT_PARSE(), e);
606: }
607: }
608:
609: return faultTo;
610: }
611:
612: /**
613: * Returns the value of WS-Addressing <code>MessageID</code> header. The <code>version</code>
614: * identifies the WS-Addressing version and the header returned is targeted at
615: * the current implicit role. Caches the value for subsequent invocation.
616: * Duplicate <code>MessageID</code> headers are detected earlier.
617: *
618: * @param av WS-Addressing version
619: * @param sv SOAP version
620: * @throws WebServiceException if either <code>av</code> or <code>sv</code> is null.
621: * @return Value of WS-Addressing MessageID header, null if no header is present
622: */
623: public String getMessageID(@NotNull
624: AddressingVersion av, @NotNull
625: SOAPVersion sv) {
626: if (messageId != null)
627: return messageId;
628:
629: if (av == null)
630: throw new IllegalArgumentException(AddressingMessages
631: .NULL_ADDRESSING_VERSION());
632:
633: Header h = getFirstHeader(av.messageIDTag, true, sv);
634: if (h != null) {
635: messageId = h.getStringContent();
636: }
637:
638: return messageId;
639: }
640:
641: /**
642: * Creates a set of outbound WS-Addressing headers on the client with the
643: * specified Action Message Addressing Property value.
644: * <p><p>
645: * This method needs to be invoked right after such a Message is
646: * created which is error prone but so far only MEX, RM and JAX-WS
647: * creates a request so this ugliness is acceptable. This method is also used
648: * to create protocol messages that are not associated with any {@link WSBinding}
649: * and {@link WSDLPort}.
650: *
651: * @param packet request packet
652: * @param av WS-Addressing version
653: * @param sv SOAP version
654: * @param oneway Indicates if the message exchange pattern is oneway
655: * @param action Action Message Addressing Property value
656: */
657: public void fillRequestAddressingHeaders(Packet packet,
658: AddressingVersion av, SOAPVersion sv, boolean oneway,
659: String action) {
660: fillCommonAddressingHeaders(packet, av, sv, action);
661:
662: // wsa:ReplyTo
663: // null or "true" is equivalent to request/response MEP
664: if (!oneway) {
665: WSEndpointReference epr = av.anonymousEpr;
666: add(epr.createHeader(av.replyToTag));
667:
668: // wsa:MessageID
669: Header h = new StringHeader(av.messageIDTag, packet
670: .getMessage().getID(av, sv));
671: add(h);
672: }
673: }
674:
675: /**
676: * Creates a set of outbound WS-Addressing headers on the client with the
677: * default Action Message Addressing Property value.
678: * <p><p>
679: * This method needs to be invoked right after such a Message is
680: * created which is error prone but so far only MEX, RM and JAX-WS
681: * creates a request so this ugliness is acceptable. If more components
682: * are identified using this, then we may revisit this.
683: * <p><p>
684: * This method is used if default Action Message Addressing Property is to
685: * be used. See
686: * {@link #fillRequestAddressingHeaders(Packet, com.sun.xml.ws.api.addressing.AddressingVersion, com.sun.xml.ws.api.SOAPVersion, boolean, String)}
687: * if non-default Action is to be used, for example when creating a protocol message not
688: * associated with {@link WSBinding} and {@link WSDLPort}.
689: * This method uses SOAPAction as the Action unless set expplicitly in the wsdl.
690: * @param wsdlPort request WSDL port
691: * @param binding request WSBinding
692: * @param packet request packet
693: */
694: public void fillRequestAddressingHeaders(WSDLPort wsdlPort,
695: @NotNull
696: WSBinding binding, Packet packet) {
697: if (binding == null)
698: throw new IllegalArgumentException(AddressingMessages
699: .NULL_BINDING());
700:
701: AddressingVersion addressingVersion = binding
702: .getAddressingVersion();
703: //seiModel is passed as null as it is not needed.
704: WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(
705: wsdlPort, null, binding);
706:
707: // wsa:Action
708: String action = wsaHelper.getEffectiveInputAction(packet);
709: if (action == null || action.equals("")) {
710: throw new WebServiceException(ClientMessages
711: .INVALID_SOAP_ACTION());
712: }
713: boolean oneway = !packet.expectReply;
714: if (wsdlPort != null) {
715: // if WSDL has <wsaw:Anonymous>prohibited</wsaw:Anonymous>, then throw an error
716: // as anonymous ReplyTo MUST NOT be added in that case. BindingProvider need to
717: // disable AddressingFeature and MemberSubmissionAddressingFeature and hand-craft
718: // the SOAP message with non-anonymous ReplyTo/FaultTo.
719: if (!oneway
720: && packet.getMessage() != null
721: && packet.getMessage().getOperation(wsdlPort) != null
722: && packet.getMessage().getOperation(wsdlPort)
723: .getAnonymous() == WSDLBoundOperation.ANONYMOUS.prohibited) {
724: throw new WebServiceException(AddressingMessages
725: .WSAW_ANONYMOUS_PROHIBITED());
726: }
727: }
728: if (!binding.isFeatureEnabled(OneWayFeature.class)) {
729: // standard oneway
730: fillRequestAddressingHeaders(packet, addressingVersion,
731: binding.getSOAPVersion(), oneway, action);
732: } else {
733: // custom oneway
734: fillRequestAddressingHeaders(packet, addressingVersion,
735: binding.getSOAPVersion(), binding
736: .getFeature(OneWayFeature.class), action);
737: }
738: }
739:
740: private void fillRequestAddressingHeaders(@NotNull
741: Packet packet, @NotNull
742: AddressingVersion av, @NotNull
743: SOAPVersion sv, @NotNull
744: OneWayFeature of, @NotNull
745: String action) {
746: fillCommonAddressingHeaders(packet, av, sv, action);
747:
748: // wsa:ReplyTo
749: if (of.getReplyTo() != null) {
750: add(of.getReplyTo().createHeader(av.replyToTag));
751:
752: // add wsa:MessageID only for non-null ReplyTo
753: Header h = new StringHeader(av.messageIDTag, packet
754: .getMessage().getID(av, sv));
755: add(h);
756: }
757:
758: // wsa:From
759: if (of.getFrom() != null) {
760: add(of.getFrom().createHeader(av.fromTag));
761: }
762:
763: // wsa:RelatesTo
764: if (of.getRelatesToID() != null) {
765: add(new RelatesToHeader(av.relatesToTag, of
766: .getRelatesToID()));
767: }
768: }
769:
770: /**
771: * Creates wsa:To, wsa:Action and wsa:MessageID header on the client
772: *
773: * @param packet request packet
774: * @param av WS-Addressing version
775: * @param sv SOAP version
776: * @param action Action Message Addressing Property value
777: * @throws IllegalArgumentException if any of the parameters is null.
778: */
779: private void fillCommonAddressingHeaders(Packet packet, @NotNull
780: AddressingVersion av, @NotNull
781: SOAPVersion sv, @NotNull
782: String action) {
783: if (packet == null)
784: throw new IllegalArgumentException(AddressingMessages
785: .NULL_PACKET());
786:
787: if (av == null)
788: throw new IllegalArgumentException(AddressingMessages
789: .NULL_ADDRESSING_VERSION());
790:
791: if (sv == null)
792: throw new IllegalArgumentException(AddressingMessages
793: .NULL_SOAP_VERSION());
794:
795: if (action == null)
796: throw new IllegalArgumentException(AddressingMessages
797: .NULL_ACTION());
798:
799: // wsa:To
800: StringHeader h = new StringHeader(av.toTag,
801: packet.endpointAddress.toString());
802: add(h);
803:
804: // wsa:Action
805: packet.soapAction = action;
806: h = new StringHeader(av.actionTag, action);
807: add(h);
808: }
809:
810: /**
811: * Adds a new {@link Header}.
812: *
813: * <p>
814: * Order doesn't matter in headers, so this method
815: * does not make any guarantee as to where the new header
816: * is inserted.
817: *
818: * @return
819: * always true. Don't use the return value.
820: */
821: public boolean add(Header header) {
822: return super .add(header);
823: }
824:
825: /**
826: * @deprecated
827: * {@link HeaderList} is monotonic and you can't remove anything.
828: */
829: // to allow this, we need to implement the resizing of understoodBits
830: public Header remove(int index) {
831: throw new UnsupportedOperationException();
832: }
833:
834: /**
835: * @deprecated
836: * {@link HeaderList} is monotonic and you can't remove anything.
837: */
838: public boolean remove(Object o) {
839: throw new UnsupportedOperationException();
840: }
841:
842: /**
843: * @deprecated
844: * {@link HeaderList} is monotonic and you can't remove anything.
845: */
846: public boolean removeAll(Collection<?> c) {
847: throw new UnsupportedOperationException();
848: }
849:
850: /**
851: * @deprecated
852: * {@link HeaderList} is monotonic and you can't remove anything.
853: */
854: public boolean retainAll(Collection<?> c) {
855: throw new UnsupportedOperationException();
856: }
857:
858: /**
859: * Creates a copy.
860: *
861: * This handles null {@link HeaderList} correctly.
862: *
863: * @param original
864: * Can be null, in which case null will be returned.
865: */
866: public static HeaderList copy(HeaderList original) {
867: if (original == null)
868: return null;
869: else
870: return new HeaderList(original);
871: }
872:
873: public void readResponseAddressingHeaders(WSDLPort wsdlPort,
874: WSBinding binding) {
875: // read Action
876: String action = getAction(binding.getAddressingVersion(),
877: binding.getSOAPVersion());
878: // TODO: validate client-inbound Action
879: }
880: }
|