| /* |
| * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| package com.sun.xml.internal.ws.api.message; |
| |
| import com.sun.istack.internal.NotNull; |
| import com.sun.istack.internal.Nullable; |
| import com.sun.xml.internal.ws.addressing.WsaTubeHelper; |
| import com.sun.xml.internal.ws.api.SOAPVersion; |
| import com.sun.xml.internal.ws.api.WSBinding; |
| import com.sun.xml.internal.ws.api.addressing.AddressingVersion; |
| import com.sun.xml.internal.ws.api.addressing.OneWayFeature; |
| import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; |
| import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; |
| import com.sun.xml.internal.ws.api.pipe.Pipe; |
| import com.sun.xml.internal.ws.api.pipe.Codec; |
| import com.sun.xml.internal.ws.message.RelatesToHeader; |
| import com.sun.xml.internal.ws.message.StringHeader; |
| import com.sun.xml.internal.ws.protocol.soap.ClientMUTube; |
| import com.sun.xml.internal.ws.protocol.soap.ServerMUTube; |
| import com.sun.xml.internal.ws.resources.AddressingMessages; |
| import com.sun.xml.internal.ws.resources.ClientMessages; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.ws.WebServiceException; |
| import java.util.ArrayList; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import java.util.Set; |
| |
| /** |
| * A list of {@link Header}s on a {@link Message}. |
| * |
| * <p> |
| * This list can be modified to add headers |
| * from outside a {@link Message}, this is necessary |
| * since intermediate processing layers often need to |
| * put additional headers. |
| * |
| * <p> |
| * Following the SOAP convention, the order among headers |
| * are not significant. However, {@link Codec}s are |
| * expected to preserve the order of headers in the input |
| * message as much as possible. |
| * |
| * |
| * <a name="MU"></a> |
| * <h3>MustUnderstand Processing</h3> |
| * <p> |
| * To perform SOAP mustUnderstang processing correctly, we need to keep |
| * track of headers that are understood and headers that are not. |
| * This is a collaborative process among {@link Pipe}s, thus it's something |
| * a {@link Pipe} author needs to keep in mind. |
| * |
| * <p> |
| * Specifically, when a {@link Pipe} sees a header and processes it |
| * (that is, if it did enough computing with the header to claim that |
| * the header is understood), then it should mark the corresponding |
| * header as "understood". For example, when a pipe that handles JAX-WSA |
| * examins the <wsa:To> header, it can claim that it understood the header. |
| * But for example, if a pipe that does the signature verification checks |
| * <wsa:To> for a signature, that would not be considered as "understood". |
| * |
| * <p> |
| * There are two ways to mark a header as understood: |
| * |
| * <ol> |
| * <li>Use one of the <tt>getXXX</tt> methods that take a |
| * boolean <tt>markAsUnderstood</tt> parameter. |
| * Most often, a {@link Pipe} knows it's going to understand a header |
| * as long as it's present, so this is the easiest and thus the preferred way. |
| * |
| * For example, if JAX-WSA looks for <wsa:To>, then it can set |
| * <tt>markAsUnderstand</tt> to true, to do the obtaining of a header |
| * and marking at the same time. |
| * |
| * <li>Call {@link #understood(int)}. |
| * If under a rare circumstance, a pipe cannot determine whether |
| * it can understand it or not when you are fetching a header, then |
| * you can use this method afterward to mark it as understood. |
| * </ol> |
| * |
| * <p> |
| * Intuitively speaking, at the end of the day, if a header is not |
| * understood but {@link Header#isIgnorable(SOAPVersion, Set)} is false, a bad thing |
| * will happen. The actual implementation of the checking is more complicated, |
| * for that see {@link ClientMUTube}/{@link ServerMUTube}. |
| * |
| * @see Message#getHeaders() |
| */ |
| public final class HeaderList extends ArrayList<Header> { |
| |
| /** |
| * Bit set to keep track of which headers are understood. |
| * <p> |
| * The first 32 headers use this field, and the rest will use |
| * {@link #moreUnderstoodBits}. The expectation is that |
| * most of the time a SOAP message will only have up to 32 headers, |
| * so we can avoid allocating separate objects for {@link BitSet}. |
| */ |
| private int understoodBits; |
| /** |
| * If there are more than 32 headers, we use this {@link BitSet} |
| * to keep track of whether those headers are understood. |
| * Lazily allocated. |
| */ |
| private BitSet moreUnderstoodBits = null; |
| |
| private String to = null; |
| private String action = null; |
| private WSEndpointReference replyTo = null; |
| private WSEndpointReference faultTo = null; |
| private String messageId; |
| |
| |
| /** |
| * Creates an empty {@link HeaderList}. |
| */ |
| public HeaderList() { |
| } |
| |
| /** |
| * Copy constructor. |
| */ |
| public HeaderList(HeaderList that) { |
| super(that); |
| this.understoodBits = that.understoodBits; |
| if(that.moreUnderstoodBits!=null) |
| this.moreUnderstoodBits = (BitSet)that.moreUnderstoodBits.clone(); |
| this.to = that.to; |
| this.action = that.action; |
| this.replyTo = that.replyTo; |
| this.faultTo = that.faultTo; |
| this.messageId = that.messageId; |
| } |
| |
| /** |
| * The number of total headers. |
| */ |
| public int size() { |
| return super.size(); |
| } |
| |
| /** |
| * Adds all the headers. |
| */ |
| public void addAll(Header... headers) { |
| for (Header header : headers) |
| add(header); |
| } |
| |
| /** |
| * Gets the {@link Header} at the specified index. |
| * |
| * <p> |
| * This method does not mark the returned {@link Header} as understood. |
| * |
| * @see #understood(int) |
| */ |
| public Header get(int index) { |
| return super.get(index); |
| } |
| |
| /** |
| * Marks the {@link Header} at the specified index as |
| * <a href="#MU">"understood"</a>. |
| */ |
| public void understood(int index) { |
| assert index<size(); // check that index is in range |
| if(index<32) |
| understoodBits |= 1<<index; |
| else { |
| if(moreUnderstoodBits==null) |
| moreUnderstoodBits = new BitSet(); |
| moreUnderstoodBits.set(index-32); |
| } |
| } |
| |
| /** |
| * Returns true if a {@link Header} at the given index |
| * was <a href="#MU">"understood"</a>. |
| */ |
| public boolean isUnderstood(int index) { |
| assert index<size(); // check that index is in range |
| if(index<32) |
| return understoodBits == (understoodBits|(1<<index)); |
| else { |
| if(moreUnderstoodBits==null) |
| return false; |
| return moreUnderstoodBits.get(index-32); |
| } |
| } |
| |
| /** |
| * Marks the specified {@link Header} as <a href="#MU">"understood"</a>. |
| * |
| * @deprecated |
| * By the deifnition of {@link ArrayList}, this operation requires |
| * O(n) search of the array, and thus inherently inefficient. |
| * |
| * Because of this, if you are developing a {@link Pipe} for |
| * a performance sensitive environment, do not use this method. |
| * |
| * @throws IllegalArgumentException |
| * if the given header is not {@link #contains(Object) contained} |
| * in this header. |
| */ |
| public void understood(@NotNull Header header) { |
| int sz = size(); |
| for( int i=0; i<sz; i++ ) { |
| if(get(i)==header) { |
| understood(i); |
| return; |
| } |
| } |
| throw new IllegalArgumentException(); |
| } |
| |
| /** |
| * Gets the first {@link Header} of the specified name. |
| * |
| * @param markAsUnderstood |
| * If this parameter is true, the returned header will |
| * be marked as <a href="#MU">"understood"</a>. |
| * @return null if not found. |
| */ |
| public @Nullable Header get(@NotNull String nsUri, @NotNull String localName, boolean markAsUnderstood) { |
| int len = size(); |
| for( int i=0; i<len; i++ ) { |
| Header h = get(i); |
| if(h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) { |
| if(markAsUnderstood) |
| understood(i); |
| return h; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @deprecated |
| * Use {@link #get(String, String, boolean)} |
| */ |
| public Header get(String nsUri, String localName) { |
| return get(nsUri,localName,true); |
| } |
| |
| /** |
| * Gets the first {@link Header} of the specified name. |
| * |
| * @param markAsUnderstood |
| * If this parameter is true, the returned header will |
| * be marked as <a href="#MU">"understood"</a>. |
| * @return null |
| * if not found. |
| */ |
| public @Nullable Header get(@NotNull QName name, boolean markAsUnderstood) { |
| return get(name.getNamespaceURI(),name.getLocalPart(),markAsUnderstood); |
| } |
| |
| /** |
| * @deprecated |
| * Use {@link #get(QName)} |
| */ |
| public @Nullable Header get(@NotNull QName name) { |
| return get(name,true); |
| } |
| |
| /** |
| * @deprecated |
| * Use {@link #getHeaders(String, String, boolean)} |
| */ |
| public Iterator<Header> getHeaders(final String nsUri, final String localName) { |
| return getHeaders(nsUri,localName,true); |
| } |
| |
| /** |
| * Gets all the {@link Header}s of the specified name, |
| * including duplicates (if any.) |
| * |
| * @param markAsUnderstood |
| * If this parameter is true, the returned headers will |
| * be marked as <a href="#MU">"understood"</a> when they are returned |
| * from {@link Iterator#next()}. |
| * @return empty iterator if not found. |
| */ |
| public @NotNull Iterator<Header> getHeaders(@NotNull final String nsUri, @NotNull final String localName, final boolean markAsUnderstood) { |
| return new Iterator<Header>() { |
| int idx = 0; |
| Header next; |
| public boolean hasNext() { |
| if(next==null) |
| fetch(); |
| return next!=null; |
| } |
| |
| public Header next() { |
| if(next==null) { |
| fetch(); |
| if(next==null) |
| throw new NoSuchElementException(); |
| } |
| |
| if(markAsUnderstood) { |
| assert get(idx-1)==next; |
| understood(idx-1); |
| } |
| |
| Header r = next; |
| next = null; |
| return r; |
| } |
| |
| private void fetch() { |
| while(idx<size()) { |
| Header h = get(idx++); |
| if(h.getLocalPart().equals(localName) && h.getNamespaceURI().equals(nsUri)) { |
| next = h; |
| break; |
| } |
| } |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| |
| /** |
| * @see #getHeaders(String, String, boolean) |
| */ |
| public @NotNull Iterator<Header> getHeaders(@NotNull QName headerName, final boolean markAsUnderstood) { |
| return getHeaders(headerName.getNamespaceURI(),headerName.getLocalPart(),markAsUnderstood); |
| } |
| |
| /** |
| * @deprecated |
| * use {@link #getHeaders(String, boolean)}. |
| */ |
| public @NotNull Iterator<Header> getHeaders(@NotNull final String nsUri) { |
| return getHeaders(nsUri,true); |
| } |
| |
| /** |
| * Gets an iteration of headers {@link Header} in the specified namespace, |
| * including duplicates (if any.) |
| * |
| * @param markAsUnderstood |
| * If this parameter is true, the returned headers will |
| * be marked as <a href="#MU">"understood"</a> when they are returned |
| * from {@link Iterator#next()}. |
| * @return |
| * empty iterator if not found. |
| */ |
| public @NotNull Iterator<Header> getHeaders(@NotNull final String nsUri, final boolean markAsUnderstood) { |
| return new Iterator<Header>() { |
| int idx = 0; |
| Header next; |
| public boolean hasNext() { |
| if(next==null) |
| fetch(); |
| return next!=null; |
| } |
| |
| public Header next() { |
| if(next==null) { |
| fetch(); |
| if(next==null) |
| throw new NoSuchElementException(); |
| } |
| |
| if(markAsUnderstood) { |
| assert get(idx-1)==next; |
| understood(idx-1); |
| } |
| |
| Header r = next; |
| next = null; |
| return r; |
| } |
| |
| private void fetch() { |
| while(idx<size()) { |
| Header h = get(idx++); |
| if(h.getNamespaceURI().equals(nsUri)) { |
| next = h; |
| break; |
| } |
| } |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| |
| /** |
| * Gets the first {@link Header} of the specified name targeted at the |
| * current implicit role. |
| * |
| * @param name name of the header |
| * @param markUnderstood |
| * If this parameter is true, the returned headers will |
| * be marked as <a href="#MU">"understood"</a> when they are returned |
| * from {@link Iterator#next()}. |
| * @return null if header not found |
| */ |
| private Header getFirstHeader(QName name, boolean markUnderstood, SOAPVersion sv) { |
| if (sv == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION()); |
| |
| Iterator<Header> iter = getHeaders(name.getNamespaceURI(), name.getLocalPart(), markUnderstood); |
| while (iter.hasNext()) { |
| Header h = iter.next(); |
| if (h.getRole(sv).equals(sv.implicitRole)) |
| return h; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the value of WS-Addressing <code>To</code> header. The <code>version</code> |
| * identifies the WS-Addressing version and the header returned is targeted at |
| * the current implicit role. Caches the value for subsequent invocation. |
| * Duplicate <code>To</code> headers are detected earlier. |
| * |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null. |
| * @return Value of WS-Addressing To header, anonymous URI if no header is present |
| */ |
| public String getTo(AddressingVersion av, SOAPVersion sv) { |
| if (to != null) |
| return to; |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| Header h = getFirstHeader(av.toTag, true, sv); |
| if (h != null) { |
| to = h.getStringContent(); |
| } else { |
| to = av.anonymousUri; |
| } |
| |
| return to; |
| } |
| |
| /** |
| * Returns the value of WS-Addressing <code>Action</code> header. The <code>version</code> |
| * identifies the WS-Addressing version and the header returned is targeted at |
| * the current implicit role. Caches the value for subsequent invocation. |
| * Duplicate <code>Action</code> headers are detected earlier. |
| * |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null. |
| * @return Value of WS-Addressing Action header, null if no header is present |
| */ |
| public String getAction(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) { |
| if (action!= null) |
| return action; |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| Header h = getFirstHeader(av.actionTag, true, sv); |
| if (h != null) { |
| action = h.getStringContent(); |
| } |
| |
| return action; |
| } |
| |
| /** |
| * Returns the value of WS-Addressing <code>ReplyTo</code> header. The <code>version</code> |
| * identifies the WS-Addressing version and the header returned is targeted at |
| * the current implicit role. Caches the value for subsequent invocation. |
| * Duplicate <code>ReplyTo</code> headers are detected earlier. |
| * |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null. |
| * @return Value of WS-Addressing ReplyTo header, null if no header is present |
| */ |
| public WSEndpointReference getReplyTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) { |
| if (replyTo!=null) |
| return replyTo; |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| Header h = getFirstHeader(av.replyToTag, true, sv); |
| if (h != null) { |
| try { |
| replyTo = h.readAsEPR(av); |
| } catch (XMLStreamException e) { |
| throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e); |
| } |
| } else { |
| replyTo = av.anonymousEpr; |
| } |
| |
| return replyTo; |
| } |
| |
| /** |
| * Returns the value of WS-Addressing <code>FaultTo</code> header. The <code>version</code> |
| * identifies the WS-Addressing version and the header returned is targeted at |
| * the current implicit role. Caches the value for subsequent invocation. |
| * Duplicate <code>FaultTo</code> headers are detected earlier. |
| * |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @throws IllegalArgumentException if either <code>av</code> or <code>sv</code> is null. |
| * @return Value of WS-Addressing FaultTo header, null if no header is present |
| */ |
| public WSEndpointReference getFaultTo(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) { |
| if (faultTo != null) |
| return faultTo; |
| |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| Header h = getFirstHeader(av.faultToTag, true, sv); |
| if (h != null) { |
| try { |
| faultTo = h.readAsEPR(av); |
| } catch (XMLStreamException e) { |
| throw new WebServiceException(AddressingMessages.FAULT_TO_CANNOT_PARSE(), e); |
| } |
| } |
| |
| return faultTo; |
| } |
| |
| /** |
| * Returns the value of WS-Addressing <code>MessageID</code> header. The <code>version</code> |
| * identifies the WS-Addressing version and the header returned is targeted at |
| * the current implicit role. Caches the value for subsequent invocation. |
| * Duplicate <code>MessageID</code> headers are detected earlier. |
| * |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @throws WebServiceException if either <code>av</code> or <code>sv</code> is null. |
| * @return Value of WS-Addressing MessageID header, null if no header is present |
| */ |
| public String getMessageID(@NotNull AddressingVersion av, @NotNull SOAPVersion sv) { |
| if (messageId != null) |
| return messageId; |
| |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| Header h = getFirstHeader(av.messageIDTag, true, sv); |
| if (h != null) { |
| messageId = h.getStringContent(); |
| } |
| |
| return messageId; |
| } |
| |
| /** |
| * Creates a set of outbound WS-Addressing headers on the client with the |
| * specified Action Message Addressing Property value. |
| * <p><p> |
| * This method needs to be invoked right after such a Message is |
| * created which is error prone but so far only MEX, RM and JAX-WS |
| * creates a request so this ugliness is acceptable. This method is also used |
| * to create protocol messages that are not associated with any {@link WSBinding} |
| * and {@link WSDLPort}. |
| * |
| * @param packet request packet |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @param oneway Indicates if the message exchange pattern is oneway |
| * @param action Action Message Addressing Property value |
| */ |
| public void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action) { |
| fillCommonAddressingHeaders(packet, av, sv, action); |
| |
| // wsa:ReplyTo |
| // null or "true" is equivalent to request/response MEP |
| if (!oneway) { |
| WSEndpointReference epr = av.anonymousEpr; |
| add(epr.createHeader(av.replyToTag)); |
| |
| // wsa:MessageID |
| Header h = new StringHeader(av.messageIDTag, packet.getMessage().getID(av, sv)); |
| add(h); |
| } |
| } |
| |
| /** |
| * Creates a set of outbound WS-Addressing headers on the client with the |
| * default Action Message Addressing Property value. |
| * <p><p> |
| * This method needs to be invoked right after such a Message is |
| * created which is error prone but so far only MEX, RM and JAX-WS |
| * creates a request so this ugliness is acceptable. If more components |
| * are identified using this, then we may revisit this. |
| * <p><p> |
| * This method is used if default Action Message Addressing Property is to |
| * be used. See |
| * {@link #fillRequestAddressingHeaders(Packet, com.sun.xml.internal.ws.api.addressing.AddressingVersion, com.sun.xml.internal.ws.api.SOAPVersion, boolean, String)} |
| * if non-default Action is to be used, for example when creating a protocol message not |
| * associated with {@link WSBinding} and {@link WSDLPort}. |
| * This method uses SOAPAction as the Action unless set expplicitly in the wsdl. |
| * @param wsdlPort request WSDL port |
| * @param binding request WSBinding |
| * @param packet request packet |
| */ |
| public void fillRequestAddressingHeaders(WSDLPort wsdlPort, @NotNull WSBinding binding, Packet packet) { |
| if (binding == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_BINDING()); |
| |
| AddressingVersion addressingVersion = binding.getAddressingVersion(); |
| //seiModel is passed as null as it is not needed. |
| WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, null, binding); |
| |
| // wsa:Action |
| String action = wsaHelper.getEffectiveInputAction(packet); |
| if (action == null || action.equals("")) { |
| throw new WebServiceException(ClientMessages.INVALID_SOAP_ACTION()); |
| } |
| boolean oneway = !packet.expectReply; |
| if (wsdlPort != null) { |
| // if WSDL has <wsaw:Anonymous>prohibited</wsaw:Anonymous>, then throw an error |
| // as anonymous ReplyTo MUST NOT be added in that case. BindingProvider need to |
| // disable AddressingFeature and MemberSubmissionAddressingFeature and hand-craft |
| // the SOAP message with non-anonymous ReplyTo/FaultTo. |
| if (!oneway && packet.getMessage() != null && packet.getMessage().getOperation(wsdlPort) != null && packet.getMessage().getOperation(wsdlPort).getAnonymous() == WSDLBoundOperation.ANONYMOUS.prohibited) |
| { |
| throw new WebServiceException(AddressingMessages.WSAW_ANONYMOUS_PROHIBITED()); |
| } |
| } |
| if (!binding.isFeatureEnabled(OneWayFeature.class)) { |
| // standard oneway |
| fillRequestAddressingHeaders(packet, addressingVersion, binding.getSOAPVersion(), oneway, action); |
| } else { |
| // custom oneway |
| fillRequestAddressingHeaders(packet, addressingVersion, binding.getSOAPVersion(), binding.getFeature(OneWayFeature.class), action); |
| } |
| } |
| |
| private void fillRequestAddressingHeaders(@NotNull Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull OneWayFeature of, @NotNull String action) { |
| fillCommonAddressingHeaders(packet, av, sv, action); |
| |
| // wsa:ReplyTo |
| if (of.getReplyTo() != null) { |
| add(of.getReplyTo().createHeader(av.replyToTag)); |
| |
| // add wsa:MessageID only for non-null ReplyTo |
| Header h = new StringHeader(av.messageIDTag, packet.getMessage().getID(av, sv)); |
| add(h); |
| } |
| |
| // wsa:From |
| if (of.getFrom() != null) { |
| add(of.getFrom().createHeader(av.fromTag)); |
| } |
| |
| // wsa:RelatesTo |
| if (of.getRelatesToID() != null) { |
| add(new RelatesToHeader(av.relatesToTag, of.getRelatesToID())); |
| } |
| } |
| |
| /** |
| * Creates wsa:To, wsa:Action and wsa:MessageID header on the client |
| * |
| * @param packet request packet |
| * @param av WS-Addressing version |
| * @param sv SOAP version |
| * @param action Action Message Addressing Property value |
| * @throws IllegalArgumentException if any of the parameters is null. |
| */ |
| private void fillCommonAddressingHeaders(Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull String action) { |
| if (packet == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_PACKET()); |
| |
| if (av == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION()); |
| |
| if (sv == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION()); |
| |
| if (action == null) |
| throw new IllegalArgumentException(AddressingMessages.NULL_ACTION()); |
| |
| // wsa:To |
| StringHeader h = new StringHeader(av.toTag, packet.endpointAddress.toString()); |
| add(h); |
| |
| // wsa:Action |
| packet.soapAction = action; |
| h = new StringHeader(av.actionTag, action); |
| add(h); |
| } |
| |
| /** |
| * Adds a new {@link Header}. |
| * |
| * <p> |
| * Order doesn't matter in headers, so this method |
| * does not make any guarantee as to where the new header |
| * is inserted. |
| * |
| * @return |
| * always true. Don't use the return value. |
| */ |
| public boolean add(Header header) { |
| return super.add(header); |
| } |
| |
| /** |
| * @deprecated |
| * {@link HeaderList} is monotonic and you can't remove anything. |
| */ |
| // to allow this, we need to implement the resizing of understoodBits |
| public Header remove(int index) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * @deprecated |
| * {@link HeaderList} is monotonic and you can't remove anything. |
| */ |
| public boolean remove(Object o) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * @deprecated |
| * {@link HeaderList} is monotonic and you can't remove anything. |
| */ |
| public boolean removeAll(Collection<?> c) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * @deprecated |
| * {@link HeaderList} is monotonic and you can't remove anything. |
| */ |
| public boolean retainAll(Collection<?> c) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Creates a copy. |
| * |
| * This handles null {@link HeaderList} correctly. |
| * |
| * @param original |
| * Can be null, in which case null will be returned. |
| */ |
| public static HeaderList copy(HeaderList original) { |
| if(original==null) |
| return null; |
| else |
| return new HeaderList(original); |
| } |
| |
| public void readResponseAddressingHeaders(WSDLPort wsdlPort, WSBinding binding) { |
| // read Action |
| String action = getAction(binding.getAddressingVersion(), binding.getSOAPVersion()); |
| // TODO: validate client-inbound Action |
| } |
| } |