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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     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  */
    26 package com.sun.xml.internal.ws.api.message;
    28 import java.util.ArrayList;
    29 import java.util.BitSet;
    30 import java.util.HashSet;
    31 import java.util.Iterator;
    32 import java.util.List;
    33 import java.util.NoSuchElementException;
    34 import java.util.Set;
    36 import javax.xml.namespace.QName;
    37 import javax.xml.ws.WebServiceException;
    39 import com.sun.istack.internal.NotNull;
    40 import com.sun.istack.internal.Nullable;
    41 import com.sun.xml.internal.ws.api.SOAPVersion;
    42 import com.sun.xml.internal.ws.api.WSBinding;
    43 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
    44 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
    45 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
    46 import com.sun.xml.internal.ws.api.pipe.Codec;
    47 import com.sun.xml.internal.ws.api.pipe.Pipe;
    48 import com.sun.xml.internal.ws.binding.SOAPBindingImpl;
    49 import com.sun.xml.internal.ws.protocol.soap.ClientMUTube;
    50 import com.sun.xml.internal.ws.protocol.soap.ServerMUTube;
    51 import java.util.Arrays;
    53 /**
    54  * A list of {@link Header}s on a {@link Message}.
    55  *
    56  * <p>
    57  * This list can be modified to add headers
    58  * from outside a {@link Message}, this is necessary
    59  * since intermediate processing layers often need to
    60  * put additional headers.
    61  *
    62  * <p>
    63  * Following the SOAP convention, the order among headers
    64  * are not significant. However, {@link Codec}s are
    65  * expected to preserve the order of headers in the input
    66  * message as much as possible.
    67  *
    68  *
    69  * <a name="MU"></a>
    70  * <h3>MustUnderstand Processing</h3>
    71  * <p>
    72  * To perform SOAP mustUnderstang processing correctly, we need to keep
    73  * track of headers that are understood and headers that are not.
    74  * This is a collaborative process among {@link Pipe}s, thus it's something
    75  * a {@link Pipe} author needs to keep in mind.
    76  *
    77  * <p>
    78  * Specifically, when a {@link Pipe} sees a header and processes it
    79  * (that is, if it did enough computing with the header to claim that
    80  * the header is understood), then it should mark the corresponding
    81  * header as "understood". For example, when a pipe that handles JAX-WSA
    82  * examins the &lt;wsa:To> header, it can claim that it understood the header.
    83  * But for example, if a pipe that does the signature verification checks
    84  * &lt;wsa:To> for a signature, that would not be considered as "understood".
    85  *
    86  * <p>
    87  * There are two ways to mark a header as understood:
    88  *
    89  * <ol>
    90  *  <li>Use one of the <tt>getXXX</tt> methods that take a
    91  *      boolean <tt>markAsUnderstood</tt> parameter.
    92  *      Most often, a {@link Pipe} knows it's going to understand a header
    93  *      as long as it's present, so this is the easiest and thus the preferred way.
    94  *
    95  *      For example, if JAX-WSA looks for &lt;wsa:To>, then it can set
    96  *      <tt>markAsUnderstand</tt> to true, to do the obtaining of a header
    97  *      and marking at the same time.
    98  *
    99  *  <li>Call {@link #understood(int)}.
   100  *      If under a rare circumstance, a pipe cannot determine whether
   101  *      it can understand it or not when you are fetching a header, then
   102  *      you can use this method afterward to mark it as understood.
   103  * </ol>
   104  *
   105  * <p>
   106  * Intuitively speaking, at the end of the day, if a header is not
   107  * understood but {@link Header#isIgnorable(SOAPVersion, java.util.Set)} is false, a bad thing
   108  * will happen. The actual implementation of the checking is more complicated,
   109  * for that see {@link ClientMUTube}/{@link ServerMUTube}.
   110  *
   111  * @see Message#getHeaders()
   112  */
   113 public class HeaderList extends ArrayList<Header> implements MessageHeaders {
   115     private static final long serialVersionUID = -6358045781349627237L;
   116     /**
   117      * Bit set to keep track of which headers are understood.
   118      * <p>
   119      * The first 32 headers use this field, and the rest will use
   120      * {@link #moreUnderstoodBits}. The expectation is that
   121      * most of the time a SOAP message will only have up to 32 headers,
   122      * so we can avoid allocating separate objects for {@link BitSet}.
   123      */
   124     private int understoodBits;
   125     /**
   126      * If there are more than 32 headers, we use this {@link BitSet}
   127      * to keep track of whether those headers are understood.
   128      * Lazily allocated.
   129      */
   130     private BitSet moreUnderstoodBits = null;
   132     private SOAPVersion soapVersion;
   134     /**
   135      * This method is deprecated - instead use this one:
   136      * public HeaderList(SOAPVersion)
   137      * Creates an empty {@link HeaderList}.
   138      */
   139     @Deprecated
   140     public HeaderList() {
   141     }
   143     /**
   144      * Creates an empty {@link HeaderList} with the given soap version
   145      * @param soapVersion
   146      */
   147     public HeaderList(SOAPVersion soapVersion) {
   148         this.soapVersion = soapVersion;
   149     }
   151     /**
   152      * Copy constructor.
   153      */
   154     public HeaderList(HeaderList that) {
   155         super(that);
   156         this.understoodBits = that.understoodBits;
   157         if (that.moreUnderstoodBits != null) {
   158             this.moreUnderstoodBits = (BitSet) that.moreUnderstoodBits.clone();
   159         }
   160     }
   162     public HeaderList(MessageHeaders that) {
   163         super(that.asList());
   164         if (that instanceof HeaderList) {
   165             HeaderList hThat = (HeaderList) that;
   166             this.understoodBits = hThat.understoodBits;
   167             if (hThat.moreUnderstoodBits != null) {
   168                 this.moreUnderstoodBits = (BitSet) hThat.moreUnderstoodBits.clone();
   169             }
   170         } else {
   171             Set<QName> understood = that.getUnderstoodHeaders();
   172             if (understood != null) {
   173                 for (QName qname : understood) {
   174                     understood(qname);
   175                 }
   176             }
   177         }
   178     }
   180     /**
   181      * The total number of headers.
   182      */
   183     @Override
   184     public int size() {
   185         return super.size();
   186     }
   188     @Override
   189     public boolean hasHeaders() {
   190         return !isEmpty();
   191     }
   193     /**
   194      * Adds all the headers.
   195      * @deprecated throws UnsupportedOperationException from some HeaderList implementations - better iterate over items one by one
   196      */
   197     @Deprecated
   198     public void addAll(Header... headers) {
   199         addAll(Arrays.asList(headers));
   200     }
   202     /**
   203      * Gets the {@link Header} at the specified index.
   204      *
   205      * <p>
   206      * This method does not mark the returned {@link Header} as understood.
   207      *
   208      * @see #understood(int)
   209      */
   210     @Override
   211     public Header get(int index) {
   212         return super.get(index);
   213     }
   215     /**
   216      * Marks the {@link Header} at the specified index as
   217      * <a href="#MU">"understood"</a>.
   218      */
   219     public void understood(int index) {
   220         // check that index is in range
   221         if (index >= size()) {
   222             throw new ArrayIndexOutOfBoundsException(index);
   223         }
   225         if (index < 32) {
   226             understoodBits |= 1 << index;
   227         } else {
   228             if (moreUnderstoodBits == null) {
   229                 moreUnderstoodBits = new BitSet();
   230             }
   231             moreUnderstoodBits.set(index - 32);
   232         }
   233     }
   235     /**
   236      * Returns true if a {@link Header} at the given index
   237      * was <a href="#MU">"understood"</a>.
   238      */
   239     public boolean isUnderstood(int index) {
   240         // check that index is in range
   241         if (index >= size()) {
   242             throw new ArrayIndexOutOfBoundsException(index);
   243         }
   245         if (index < 32) {
   246             return understoodBits == (understoodBits | (1 << index));
   247         } else {
   248             if (moreUnderstoodBits == null) {
   249                 return false;
   250             }
   251             return moreUnderstoodBits.get(index - 32);
   252         }
   253     }
   255     /**
   256      * Marks the specified {@link Header} as <a href="#MU">"understood"</a>.
   257      *
   258      * @deprecated
   259      * By the definition of {@link ArrayList}, this operation requires
   260      * O(n) search of the array, and thus inherently inefficient.
   261      *
   262      * Because of this, if you are developing a {@link Pipe} for
   263      * a performance sensitive environment, do not use this method.
   264      *
   265      * @throws IllegalArgumentException
   266      *      if the given header is not {@link #contains(Object) contained}
   267      *      in this header.
   268      */
   269     @Override
   270     public void understood(@NotNull Header header) {
   271         int sz = size();
   272         for (int i = 0; i < sz; i++) {
   273             if (get(i) == header) {
   274                 understood(i);
   275                 return;
   276             }
   277         }
   278         throw new IllegalArgumentException();
   279     }
   281     /**
   282      * Gets the first {@link Header} of the specified name.
   283      *
   284      * @param markAsUnderstood
   285      *      If this parameter is true, the returned header will
   286      *      be marked as <a href="#MU">"understood"</a>.
   287      * @return null if not found.
   288      */
   289     @Override
   290     public @Nullable Header get(@NotNull String nsUri, @NotNull String localName, boolean markAsUnderstood) {
   291         int len = size();
   292         for (int i = 0; i < len; i++) {
   293             Header h = get(i);
   294             if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
   295                 if (markAsUnderstood) {
   296                     understood(i);
   297                 }
   298                 return h;
   299             }
   300         }
   301         return null;
   302     }
   304     /**
   305      * @deprecated
   306      *      Use {@link #get(String, String, boolean)}
   307      */
   308     public Header get(String nsUri, String localName) {
   309         return get(nsUri, localName, true);
   310     }
   312     /**
   313      * Gets the first {@link Header} of the specified name.
   314      *
   315      * @param markAsUnderstood
   316      *      If this parameter is true, the returned header will
   317      *      be marked as <a href="#MU">"understood"</a>.
   318      * @return null
   319      *      if not found.
   320      */
   321     @Override
   322     public @Nullable Header get(@NotNull QName name, boolean markAsUnderstood) {
   323         return get(name.getNamespaceURI(), name.getLocalPart(), markAsUnderstood);
   324     }
   326     /**
   327      * @deprecated
   328      *      Use {@link #get(QName)}
   329      */
   330     public
   331     @Nullable
   332     Header get(@NotNull QName name) {
   333         return get(name, true);
   334     }
   336     /**
   337      * @deprecated
   338      *      Use {@link #getHeaders(String, String, boolean)}
   339      */
   340     public Iterator<Header> getHeaders(final String nsUri, final String localName) {
   341         return getHeaders(nsUri, localName, true);
   342     }
   344     /**
   345      * Gets all the {@link Header}s of the specified name,
   346      * including duplicates (if any.)
   347      *
   348      * @param markAsUnderstood
   349      *      If this parameter is true, the returned headers will
   350      *      be marked as <a href="#MU">"understood"</a> when they are returned
   351      *      from {@link Iterator#next()}.
   352      * @return empty iterator if not found.
   353      */
   354     public
   355     @NotNull
   356     @Override
   357     Iterator<Header> getHeaders(@NotNull final String nsUri, @NotNull final String localName, final boolean markAsUnderstood) {
   358         return new Iterator<Header>() {
   360             int idx = 0;
   361             Header next;
   363             @Override
   364             public boolean hasNext() {
   365                 if (next == null) {
   366                     fetch();
   367                 }
   368                 return next != null;
   369             }
   371             @Override
   372             public Header next() {
   373                 if (next == null) {
   374                     fetch();
   375                     if (next == null) {
   376                         throw new NoSuchElementException();
   377                     }
   378                 }
   380                 if (markAsUnderstood) {
   381                     assert get(idx - 1) == next;
   382                     understood(idx - 1);
   383                 }
   385                 Header r = next;
   386                 next = null;
   387                 return r;
   388             }
   390             private void fetch() {
   391                 while (idx < size()) {
   392                     Header h = get(idx++);
   393                     if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
   394                         next = h;
   395                         break;
   396                     }
   397                 }
   398             }
   400             @Override
   401             public void remove() {
   402                 throw new UnsupportedOperationException();
   403             }
   404         };
   405     }
   407     /**
   408      * @see #getHeaders(String, String, boolean)
   409      */
   410     public
   411     @NotNull
   412     @Override
   413     Iterator<Header> getHeaders(@NotNull QName headerName, final boolean markAsUnderstood) {
   414         return getHeaders(headerName.getNamespaceURI(), headerName.getLocalPart(), markAsUnderstood);
   415     }
   417     /**
   418      * @deprecated
   419      *      use {@link #getHeaders(String, boolean)}.
   420      */
   421     public
   422     @NotNull
   423     Iterator<Header> getHeaders(@NotNull final String nsUri) {
   424         return getHeaders(nsUri, true);
   425     }
   427     /**
   428      * Gets an iteration of headers {@link Header} in the specified namespace,
   429      * including duplicates (if any.)
   430      *
   431      * @param markAsUnderstood
   432      *      If this parameter is true, the returned headers will
   433      *      be marked as <a href="#MU">"understood"</a> when they are returned
   434      *      from {@link Iterator#next()}.
   435      * @return
   436      *      empty iterator if not found.
   437      */
   438     public
   439     @NotNull
   440     @Override
   441     Iterator<Header> getHeaders(@NotNull final String nsUri, final boolean markAsUnderstood) {
   442         return new Iterator<Header>() {
   444             int idx = 0;
   445             Header next;
   447             @Override
   448             public boolean hasNext() {
   449                 if (next == null) {
   450                     fetch();
   451                 }
   452                 return next != null;
   453             }
   455             @Override
   456             public Header next() {
   457                 if (next == null) {
   458                     fetch();
   459                     if (next == null) {
   460                         throw new NoSuchElementException();
   461                     }
   462                 }
   464                 if (markAsUnderstood) {
   465                     assert get(idx - 1) == next;
   466                     understood(idx - 1);
   467                 }
   469                 Header r = next;
   470                 next = null;
   471                 return r;
   472             }
   474             private void fetch() {
   475                 while (idx < size()) {
   476                     Header h = get(idx++);
   477                     if (h.getNamespaceURI().equals(nsUri)) {
   478                         next = h;
   479                         break;
   480                     }
   481                 }
   482             }
   484             @Override
   485             public void remove() {
   486                 throw new UnsupportedOperationException();
   487             }
   488         };
   489     }
   491     /**
   492      * Returns the value of WS-Addressing <code>To</code> header. The <code>version</code>
   493      * identifies the WS-Addressing version and the header returned is targeted at
   494      * the current implicit role. Caches the value for subsequent invocation.
   495      * Duplicate <code>To</code> headers are detected earlier.
   496      *
   497      * @param av WS-Addressing version
   498      * @param sv SOAP version
   499      * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
   500      * @return Value of WS-Addressing To header, anonymous URI if no header is present
   501      */
   502     public String getTo(AddressingVersion av, SOAPVersion sv) {
   503         return AddressingUtils.getTo(this, av, sv);
   504     }
   506     /**
   507      * Returns the value of WS-Addressing <code>Action</code> header. The <code>version</code>
   508      * identifies the WS-Addressing version and the header returned is targeted at
   509      * the current implicit role. Caches the value for subsequent invocation.
   510      * Duplicate <code>Action</code> headers are detected earlier.
   511      *
   512      * @param av WS-Addressing version
   513      * @param sv SOAP version
   514      * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
   515      * @return Value of WS-Addressing Action header, null if no header is present
   516      */
   517     public String getAction(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   518         return AddressingUtils.getAction(this, av, sv);
   519     }
   521     /**
   522      * Returns the value of WS-Addressing <code>ReplyTo</code> header. The <code>version</code>
   523      * identifies the WS-Addressing version and the header returned is targeted at
   524      * the current implicit role. Caches the value for subsequent invocation.
   525      * Duplicate <code>ReplyTo</code> headers are detected earlier.
   526      *
   527      * @param av WS-Addressing version
   528      * @param sv SOAP version
   529      * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
   530      * @return Value of WS-Addressing ReplyTo header, null if no header is present
   531      */
   532     public WSEndpointReference getReplyTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   533         return AddressingUtils.getReplyTo(this, av, sv);
   534     }
   536     /**
   537      * Returns the value of WS-Addressing <code>FaultTo</code> header. The <code>version</code>
   538      * identifies the WS-Addressing version and the header returned is targeted at
   539      * the current implicit role. Caches the value for subsequent invocation.
   540      * Duplicate <code>FaultTo</code> headers are detected earlier.
   541      *
   542      * @param av WS-Addressing version
   543      * @param sv SOAP version
   544      * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null.
   545      * @return Value of WS-Addressing FaultTo header, null if no header is present
   546      */
   547     public WSEndpointReference getFaultTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   548         return AddressingUtils.getFaultTo(this, av, sv);
   549     }
   551     /**
   552      * Returns the value of WS-Addressing <code>MessageID</code> header. The <code>version</code>
   553      * identifies the WS-Addressing version and the header returned is targeted at
   554      * the current implicit role. Caches the value for subsequent invocation.
   555      * Duplicate <code>MessageID</code> headers are detected earlier.
   556      *
   557      * @param av WS-Addressing version
   558      * @param sv SOAP version
   559      * @throws WebServiceException if either <code>av</code> or <code>sv</code> is null.
   560      * @return Value of WS-Addressing MessageID header, null if no header is present
   561      */
   562     public String getMessageID(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   563         return AddressingUtils.getMessageID(this, av, sv);
   564     }
   566     /**
   567      * Returns the value of WS-Addressing <code>RelatesTo</code> header. The <code>version</code>
   568      * identifies the WS-Addressing version and the header returned is targeted at
   569      * the current implicit role. Caches the value for subsequent invocation.
   570      * Duplicate <code>RelatesTo</code> headers are detected earlier.
   571      *
   572      * @param av WS-Addressing version
   573      * @param sv SOAP version
   574      * @throws WebServiceException if either <code>av</code> or <code>sv</code> is null.
   575      * @return Value of WS-Addressing RelatesTo header, null if no header is present
   576      */
   577     public String getRelatesTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
   578         return AddressingUtils.getRelatesTo(this, av, sv);
   579     }
   581     /**
   582      * Creates a set of outbound WS-Addressing headers on the client with the
   583      * specified Action Message Addressing Property value.
   584      * <p><p>
   585      * This method needs to be invoked right after such a Message is
   586      * created which is error prone but so far only MEX, RM and JAX-WS
   587      * creates a request so this ugliness is acceptable. This method is also used
   588      * to create protocol messages that are not associated with any {@link WSBinding}
   589      * and {@link WSDLPort}.
   590      *
   591      * @param packet request packet
   592      * @param av WS-Addressing version
   593      * @param sv SOAP version
   594      * @param oneway Indicates if the message exchange pattern is oneway
   595      * @param action Action Message Addressing Property value
   596      * @param mustUnderstand to indicate if the addressing headers are set with mustUnderstand attribute
   597      */
   598     public void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action, boolean mustUnderstand) {
   599         AddressingUtils.fillRequestAddressingHeaders(this, packet, av, sv, oneway, action, mustUnderstand);
   600     }
   602     public void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action) {
   603         AddressingUtils.fillRequestAddressingHeaders(this, packet, av, sv, oneway, action);
   604     }
   606     /**
   607      * Creates a set of outbound WS-Addressing headers on the client with the
   608      * default Action Message Addressing Property value.
   609      * <p><p>
   610      * This method needs to be invoked right after such a Message is
   611      * created which is error prone but so far only MEX, RM and JAX-WS
   612      * creates a request so this ugliness is acceptable. If more components
   613      * are identified using this, then we may revisit this.
   614      * <p><p>
   615      * This method is used if default Action Message Addressing Property is to
   616      * be used. See
   617      * {@link #fillRequestAddressingHeaders(Packet, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, boolean, String)}
   618      * if non-default Action is to be used, for example when creating a protocol message not
   619      * associated with {@link WSBinding} and {@link WSDLPort}.
   620      * This method uses SOAPAction as the Action unless set expplicitly in the wsdl.
   621      * @param wsdlPort request WSDL port
   622      * @param binding request WSBinding
   623      * @param packet request packet
   624      */
   625     public void fillRequestAddressingHeaders(WSDLPort wsdlPort, @NotNull WSBinding binding, Packet packet) {
   626         AddressingUtils.fillRequestAddressingHeaders(this, wsdlPort, binding, packet);
   627     }
   629     /**
   630      * Adds a new {@link Header}.
   631      *
   632      * <p>
   633      * Order doesn't matter in headers, so this method
   634      * does not make any guarantee as to where the new header
   635      * is inserted.
   636      *
   637      * @return
   638      *      always true. Don't use the return value.
   639      */
   640     @Override
   641     public boolean add(Header header) {
   642         return super.add(header);
   643     }
   645     /**
   646      * Removes the first {@link Header} of the specified name.
   647      * @param nsUri namespace URI of the header to remove
   648      * @param localName local part of the FQN of the header to remove
   649      *
   650      * @return null if not found.
   651      */
   652     public
   653     @Nullable
   654     @Override
   655     Header remove(@NotNull String nsUri, @NotNull String localName) {
   656         int len = size();
   657         for (int i = 0; i < len; i++) {
   658             Header h = get(i);
   659             if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
   660                 return remove(i);
   661             }
   662         }
   663         return null;
   664     }
   666     /**
   667      * Replaces an existing {@link Header} or adds a new {@link Header}.
   668      *
   669      * <p>
   670      * Order doesn't matter in headers, so this method
   671      * does not make any guarantee as to where the new header
   672      * is inserted.
   673      *
   674      * @return
   675      *      always true. Don't use the return value.
   676      */
   677     @Override
   678     public boolean addOrReplace(Header header) {
   679         for (int i=0; i < size(); i++) {
   680           Header hdr = get(i);
   681           if (hdr.getNamespaceURI().equals(header.getNamespaceURI()) &&
   682               hdr.getLocalPart().equals(header.getLocalPart())) {
   683             // Put the new header in the old position. Call super versions
   684             // internally to avoid UnsupportedOperationException
   685             removeInternal(i);
   686             addInternal(i, header);
   687             return true;
   688           }
   689         }
   690         return add(header);
   691     }
   693     @Override
   694     public void replace(Header old, Header header) {
   695         for (int i=0; i < size(); i++) {
   696             Header hdr = get(i);
   697             if (hdr.getNamespaceURI().equals(header.getNamespaceURI()) &&
   698                 hdr.getLocalPart().equals(header.getLocalPart())) {
   699               // Put the new header in the old position. Call super versions
   700               // internally to avoid UnsupportedOperationException
   701               removeInternal(i);
   702               addInternal(i, header);
   703               return;
   704             }
   705           }
   707           throw new IllegalArgumentException();
   708     }
   710     protected void addInternal(int index, Header header) {
   711         super.add(index, header);
   712     }
   714     protected Header removeInternal(int index) {
   715         return super.remove(index);
   716     }
   718     /**
   719      * Removes the first {@link Header} of the specified name.
   720      *
   721      * @param name fully qualified name of the header to remove
   722      *
   723      * @return null if not found.
   724      */
   725     public
   726     @Nullable
   727     @Override
   728     Header remove(@NotNull QName name) {
   729         return remove(name.getNamespaceURI(), name.getLocalPart());
   730     }
   732     /**
   733      * Removes the first {@link Header} of the specified name.
   734      *
   735      * @param index index of the header to remove
   736      *
   737      * @return removed header
   738      */
   739     @Override
   740     public Header remove(int index) {
   741         removeUnderstoodBit(index);
   742         return super.remove(index);
   743     }
   745     /**
   746      * Removes the "understood" bit for header on the position specified by {@code index} parameter
   747      * from the set of understood header bits.
   748      *
   749      * @param index position of the bit to remove
   750      */
   751     private void removeUnderstoodBit(int index) {
   752         assert index < size();
   754         if (index < 32) {
   755             /**
   756              * Let
   757              *   R be the bit to be removed
   758              *   M be a more significant "upper" bit than bit R
   759              *   L be a less significant "lower" bit than bit R
   760              *
   761              * Then following 3 lines of code produce these results:
   762              *
   763              *   old understoodBits = MMMMMMMMMMMMRLLLLLLLLLLLLLLLLLLL
   764              *
   765              *   shiftedUpperBits   = 0MMMMMMMMMMMM0000000000000000000
   766              *
   767              *   lowerBits          = 0000000000000LLLLLLLLLLLLLLLLLLL
   768              *
   769              *   new understoodBits = 0MMMMMMMMMMMMLLLLLLLLLLLLLLLLLLL
   770              *
   771              * The R bit is removed and all the upper bits are shifted right (unsigned)
   772              */
   773             int shiftedUpperBits = understoodBits >>> -31 + index << index;
   774             int lowerBits = understoodBits << -index >>> 31 - index >>> 1;
   775             understoodBits = shiftedUpperBits | lowerBits;
   777             if (moreUnderstoodBits != null && moreUnderstoodBits.cardinality() > 0) {
   778                 if (moreUnderstoodBits.get(0)) {
   779                     understoodBits |= 0x80000000;
   780                 }
   782                 moreUnderstoodBits.clear(0);
   783                 for (int i = moreUnderstoodBits.nextSetBit(1); i > 0; i = moreUnderstoodBits.nextSetBit(i + 1)) {
   784                     moreUnderstoodBits.set(i - 1);
   785                     moreUnderstoodBits.clear(i);
   786                 }
   787             }
   788         } else if (moreUnderstoodBits != null && moreUnderstoodBits.cardinality() > 0) {
   789             index -= 32;
   790             moreUnderstoodBits.clear(index);
   791             for (int i = moreUnderstoodBits.nextSetBit(index); i >= 1; i = moreUnderstoodBits.nextSetBit(i + 1)) {
   792                 moreUnderstoodBits.set(i - 1);
   793                 moreUnderstoodBits.clear(i);
   794             }
   795         }
   797         // remove bit set if the new size will be < 33 => we fit all bits into int
   798         if (size() - 1 <= 33 && moreUnderstoodBits != null) {
   799             moreUnderstoodBits = null;
   800         }
   801     }
   803     /**
   804      * Removes a single instance of the specified element from this
   805      * header list, if it is present.  More formally,
   806      * removes a header <tt>h</tt> such that <tt>(o==null ? h==null :
   807      * o.equals(h))</tt>, if the header list contains one or more such
   808      * headers.  Returns <tt>true</tt> if the list contained the
   809      * specified element (or equivalently, if the list changed as a
   810      * result of the call).<p>
   811      *
   812      * @param o element to be removed from this list, if present.
   813      * @return <tt>true</tt> if the list contained the specified element.
   814      * @see #remove(javax.xml.namespace.QName)
   815      */
   816     @Override
   817     public boolean remove(Object o) {
   818         if (o != null) {
   819             for (int index = 0; index < this.size(); index++) {
   820                 if (o.equals(this.get(index))) {
   821                     remove(index);
   822                     return true;
   823                 }
   824             }
   825         }
   827         return false;
   828     }
   830     public Header remove(Header h) {
   831         if (remove((Object) h)) {
   832             return h;
   833         } else {
   834             return null;
   835         }
   836     }
   838     /**
   839      * Creates a copy.
   840      *
   841      * This handles null {@link HeaderList} correctly.
   842      *
   843      * @param original
   844      *      Can be null, in which case null will be returned.
   845      */
   846     public static HeaderList copy(MessageHeaders original) {
   847         if (original == null) {
   848             return null;
   849         } else {
   850             return new HeaderList(original);
   851         }
   852     }
   854     /**
   855      * Creates a copy.
   856      *
   857      * This handles null {@link HeaderList} correctly.
   858      *
   859      * @param original
   860      *      Can be null, in which case null will be returned.
   861      */
   862     public static HeaderList copy(HeaderList original) {
   863         return copy((MessageHeaders) original);
   864     }
   866     public void readResponseAddressingHeaders(WSDLPort wsdlPort, WSBinding binding) {
   867         // read Action
   868 //        String wsaAction = getAction(binding.getAddressingVersion(), binding.getSOAPVersion());
   869         // TODO: validate client-inbound Action
   870     }
   872     @Override
   873     public void understood(QName name) {
   874        get(name, true);
   875     }
   877     @Override
   878     public void understood(String nsUri, String localName) {
   879         get(nsUri, localName, true);
   880     }
   882     @Override
   883     public Set<QName> getUnderstoodHeaders() {
   884         Set<QName> understoodHdrs = new HashSet<QName>();
   885         for (int i = 0; i < size(); i++) {
   886             if (isUnderstood(i)) {
   887                 Header header = get(i);
   888                 understoodHdrs.add(new QName(header.getNamespaceURI(), header.getLocalPart()));
   889             }
   890         }
   891         return understoodHdrs;
   892 //        throw new UnsupportedOperationException("getUnderstoodHeaders() is not implemented by HeaderList");
   893     }
   895     @Override
   896     public boolean isUnderstood(Header header) {
   897         return isUnderstood(header.getNamespaceURI(), header.getLocalPart());
   898     }
   900     @Override
   901     public boolean isUnderstood(String nsUri, String localName) {
   902         for (int i = 0; i < size(); i++) {
   903             Header h = get(i);
   904             if (h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) {
   905                 return isUnderstood(i);
   906             }
   907         }
   908         return false;
   909     }
   911     @Override
   912     public boolean isUnderstood(QName name) {
   913         return isUnderstood(name.getNamespaceURI(), name.getLocalPart());
   914     }
   916     @Override
   917     public Set<QName> getNotUnderstoodHeaders(Set<String> roles, Set<QName> knownHeaders, WSBinding binding) {
   918         Set<QName> notUnderstoodHeaders = null;
   919         if (roles == null) {
   920             roles = new HashSet<String>();
   921         }
   922         SOAPVersion effectiveSoapVersion = getEffectiveSOAPVersion(binding);
   923         roles.add(effectiveSoapVersion.implicitRole);
   924         for (int i = 0; i < size(); i++) {
   925             if (!isUnderstood(i)) {
   926                 Header header = get(i);
   927                 if (!header.isIgnorable(effectiveSoapVersion, roles)) {
   928                     QName qName = new QName(header.getNamespaceURI(), header.getLocalPart());
   929                     if (binding == null) {
   930                         //if binding is null, no further checks needed...we already
   931                         //know this header is not understood from the isUnderstood
   932                         //check above
   933                         if (notUnderstoodHeaders == null) {
   934                             notUnderstoodHeaders = new HashSet<QName>();
   935                         }
   936                         notUnderstoodHeaders.add(qName);
   937                     } else {
   938                         // if the binding is not null, see if the binding can understand it
   939                         if (binding instanceof SOAPBindingImpl && !((SOAPBindingImpl) binding).understandsHeader(qName)) {
   940                             if (!knownHeaders.contains(qName)) {
   941                                 //logger.info("Element not understood=" + qName);
   942                                 if (notUnderstoodHeaders == null) {
   943                                     notUnderstoodHeaders = new HashSet<QName>();
   944                                 }
   945                                 notUnderstoodHeaders.add(qName);
   946                             }
   947                         }
   948                     }
   949                 }
   950             }
   951         }
   952         return notUnderstoodHeaders;
   953     }
   955     private SOAPVersion getEffectiveSOAPVersion(WSBinding binding) {
   956         SOAPVersion mySOAPVersion = (soapVersion != null) ? soapVersion : binding.getSOAPVersion();
   957         if (mySOAPVersion == null) {
   958             mySOAPVersion = SOAPVersion.SOAP_11;
   959         }
   960         return mySOAPVersion;
   961     }
   963     public void setSoapVersion(SOAPVersion soapVersion) {
   964        this.soapVersion = soapVersion;
   965     }
   967     @Override
   968     public Iterator<Header> getHeaders() {
   969         return iterator();
   970     }
   972     @Override
   973     public List<Header> asList() {
   974         return this;
   975     }
   976 }

mercurial