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

Wed, 12 Jun 2013 14:47:09 +0100

author
mkos
date
Wed, 12 Jun 2013 14:47:09 +0100
changeset 384
8f2986ff0235
parent 368
0989ad8c0860
child 637
9c07ef4934dd
permissions
-rw-r--r--

8013021: Rebase 8005432 & 8003542 against the latest jdk8/jaxws
8003542: Improve processing of MTOM attachments
8005432: Update access to JAX-WS
Reviewed-by: mullan

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

mercurial