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 */
25
26package com.sun.xml.internal.ws.api.message;
27
28import java.util.Iterator;
29
30import javax.xml.namespace.QName;
31import javax.xml.stream.XMLStreamException;
32import javax.xml.ws.WebServiceException;
33import javax.xml.ws.soap.SOAPBinding;
34
35import com.sun.istack.internal.NotNull;
36import com.sun.xml.internal.ws.addressing.WsaTubeHelper;
37import com.sun.xml.internal.ws.api.SOAPVersion;
38import com.sun.xml.internal.ws.api.WSBinding;
39import com.sun.xml.internal.ws.api.addressing.AddressingPropertySet;
40import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
41import com.sun.xml.internal.ws.api.addressing.OneWayFeature;
42import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
43import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
44import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
45import com.sun.xml.internal.ws.message.RelatesToHeader;
46import com.sun.xml.internal.ws.message.StringHeader;
47import com.sun.xml.internal.ws.resources.AddressingMessages;
48import com.sun.xml.internal.ws.resources.ClientMessages;
49
50public class AddressingUtils {
51    //TODO is MessageHeaders to be implicitly assumed? Or moved to utility class and taken out from interface?
52    public static void fillRequestAddressingHeaders(MessageHeaders headers, Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action) {
53        fillRequestAddressingHeaders(headers, packet, av, sv, oneway, action, false);
54    }
55    public static void fillRequestAddressingHeaders(MessageHeaders headers, Packet packet, AddressingVersion av, SOAPVersion sv, boolean oneway, String action, boolean mustUnderstand) {
56        fillCommonAddressingHeaders(headers, packet, av, sv, action, mustUnderstand);
57
58        // wsa:ReplyTo
59        // null or "true" is equivalent to request/response MEP
60        if (!oneway) {
61            WSEndpointReference epr = av.anonymousEpr;
62            if (headers.get(av.replyToTag, false) == null) {
63              headers.add(epr.createHeader(av.replyToTag));
64            }
65
66            // wsa:FaultTo
67            if (headers.get(av.faultToTag, false) == null) {
68              headers.add(epr.createHeader(av.faultToTag));
69            }
70
71            // wsa:MessageID
72            if (packet.getMessage().getHeaders().get(av.messageIDTag, false) == null) {
73                if (headers.get(av.messageIDTag, false) == null) {
74                    Header h = new StringHeader(av.messageIDTag, Message.generateMessageID());
75                    headers.add(h);
76                }
77            }
78        }
79    }
80//  private void fillRequestAddressingHeaders(Packet packet, AddressingVersion av, SOAPVersion sv, OneWayFeature oneWayFeature, boolean oneway, String action);
81    public static void fillRequestAddressingHeaders(MessageHeaders headers, WSDLPort wsdlPort, WSBinding binding, Packet packet) {
82        if (binding == null) {
83            throw new IllegalArgumentException(AddressingMessages.NULL_BINDING());
84        }
85
86        if (binding.isFeatureEnabled(SuppressAutomaticWSARequestHeadersFeature.class)) {
87            return;
88        }
89
90        //See if WSA headers are already set by the user.
91        MessageHeaders hl = packet.getMessage().getHeaders();
92        String action = AddressingUtils.getAction(hl, binding.getAddressingVersion(), binding.getSOAPVersion());
93        if (action != null) {
94            //assume that all the WSA headers are set by the user
95            return;
96        }
97        AddressingVersion addressingVersion = binding.getAddressingVersion();
98        //seiModel is passed as null as it is not needed.
99        WsaTubeHelper wsaHelper = addressingVersion.getWsaHelper(wsdlPort, null, binding);
100
101        // wsa:Action
102        String effectiveInputAction = wsaHelper.getEffectiveInputAction(packet);
103        if (effectiveInputAction == null || effectiveInputAction.equals("") && binding.getSOAPVersion() == SOAPVersion.SOAP_11) {
104            throw new WebServiceException(ClientMessages.INVALID_SOAP_ACTION());
105        }
106        boolean oneway = !packet.expectReply;
107        if (wsdlPort != null) {
108            // if WSDL has <wsaw:Anonymous>prohibited</wsaw:Anonymous>, then throw an error
109            // as anonymous ReplyTo MUST NOT be added in that case. BindingProvider need to
110            // disable AddressingFeature and MemberSubmissionAddressingFeature and hand-craft
111            // the SOAP message with non-anonymous ReplyTo/FaultTo.
112            if (!oneway && packet.getMessage() != null && packet.getWSDLOperation() != null) {
113                WSDLBoundOperation wbo = wsdlPort.getBinding().get(packet.getWSDLOperation());
114                if (wbo != null && wbo.getAnonymous() == WSDLBoundOperation.ANONYMOUS.prohibited) {
115                    throw new WebServiceException(AddressingMessages.WSAW_ANONYMOUS_PROHIBITED());
116                }
117            }
118        }
119
120        OneWayFeature oneWayFeature = binding.getFeature(OneWayFeature.class);
121        final AddressingPropertySet addressingPropertySet = packet.getSatellite(AddressingPropertySet.class);
122        oneWayFeature = addressingPropertySet == null ? oneWayFeature : new OneWayFeature(addressingPropertySet, addressingVersion);
123
124        if (oneWayFeature == null || !oneWayFeature.isEnabled()) {
125            // standard oneway
126            fillRequestAddressingHeaders(headers, packet, addressingVersion, binding.getSOAPVersion(), oneway, effectiveInputAction, AddressingVersion.isRequired(binding));
127        } else {
128            // custom oneway
129            fillRequestAddressingHeaders(headers, packet, addressingVersion, binding.getSOAPVersion(), oneWayFeature, oneway, effectiveInputAction);
130        }
131    }
132
133    public static String getAction(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
134        if (av == null) {
135            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
136        }
137
138        String action = null;
139        Header h = getFirstHeader(headers, av.actionTag, true, sv);
140        if (h != null) {
141            action = h.getStringContent();
142        }
143
144        return action;
145    }
146
147    public static WSEndpointReference getFaultTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
148        if (av == null) {
149            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
150        }
151
152        Header h = getFirstHeader(headers, av.faultToTag, true, sv);
153        WSEndpointReference faultTo = null;
154        if (h != null) {
155            try {
156                faultTo = h.readAsEPR(av);
157            } catch (XMLStreamException e) {
158                throw new WebServiceException(AddressingMessages.FAULT_TO_CANNOT_PARSE(), e);
159            }
160        }
161
162        return faultTo;
163    }
164
165    public static String getMessageID(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
166        if (av == null) {
167            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
168        }
169
170        Header h = getFirstHeader(headers, av.messageIDTag, true, sv);
171        String messageId = null;
172        if (h != null) {
173            messageId = h.getStringContent();
174        }
175
176        return messageId;
177    }
178    public static String getRelatesTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
179        if (av == null) {
180            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
181        }
182
183        Header h = getFirstHeader(headers, av.relatesToTag, true, sv);
184        String relatesTo = null;
185        if (h != null) {
186            relatesTo = h.getStringContent();
187        }
188
189        return relatesTo;
190    }
191    public static WSEndpointReference getReplyTo(@NotNull MessageHeaders headers, @NotNull AddressingVersion av, @NotNull SOAPVersion sv) {
192        if (av == null) {
193            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
194        }
195
196        Header h = getFirstHeader(headers, av.replyToTag, true, sv);
197        WSEndpointReference replyTo;
198        if (h != null) {
199            try {
200                replyTo = h.readAsEPR(av);
201            } catch (XMLStreamException e) {
202                throw new WebServiceException(AddressingMessages.REPLY_TO_CANNOT_PARSE(), e);
203            }
204        } else {
205            replyTo = av.anonymousEpr;
206        }
207
208        return replyTo;
209    }
210    public static String getTo(MessageHeaders headers, AddressingVersion av, SOAPVersion sv) {
211        if (av == null) {
212            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
213        }
214
215        Header h = getFirstHeader(headers, av.toTag, true, sv);
216        String to;
217        if (h != null) {
218            to = h.getStringContent();
219        } else {
220            to = av.anonymousUri;
221        }
222
223        return to;
224    }
225
226    public static Header getFirstHeader(MessageHeaders headers, QName name, boolean markUnderstood, SOAPVersion sv) {
227        if (sv == null) {
228            throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION());
229        }
230
231        Iterator<Header> iter = headers.getHeaders(name.getNamespaceURI(), name.getLocalPart(), markUnderstood);
232        while (iter.hasNext()) {
233            Header h = iter.next();
234            if (h.getRole(sv).equals(sv.implicitRole)) {
235                return h;
236            }
237        }
238
239        return null;
240    }
241
242    private static void fillRequestAddressingHeaders(@NotNull MessageHeaders headers, @NotNull Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull OneWayFeature oneWayFeature, boolean oneway, @NotNull String action) {
243        if (!oneway&&!oneWayFeature.isUseAsyncWithSyncInvoke() && Boolean.TRUE.equals(packet.isSynchronousMEP)) {
244            fillRequestAddressingHeaders(headers, packet, av, sv, oneway, action);
245        } else {
246            fillCommonAddressingHeaders(headers, packet, av, sv, action, false);
247
248            boolean isMessageIdAdded = false;
249
250            // wsa:ReplyTo
251            // add if it doesn't already exist and OneWayFeature requests a specific ReplyTo
252            if (headers.get(av.replyToTag, false) == null) {
253                WSEndpointReference replyToEpr = oneWayFeature.getReplyTo();
254                if (replyToEpr != null) {
255                    headers.add(replyToEpr.createHeader(av.replyToTag));
256                    // add wsa:MessageID only for non-null ReplyTo
257                    if (packet.getMessage().getHeaders().get(av.messageIDTag, false) == null) {
258                        // if header doesn't exist, method getID creates a new random id
259                        String newID = oneWayFeature.getMessageId() == null ? Message.generateMessageID() : oneWayFeature.getMessageId();
260                        headers.add(new StringHeader(av.messageIDTag, newID));
261                        isMessageIdAdded = true;
262                    }
263                }
264            }
265
266            // If the user sets a messageId, use it.
267            final String messageId = oneWayFeature.getMessageId();
268            if (!isMessageIdAdded && messageId != null) {
269                headers.add(new StringHeader(av.messageIDTag, messageId));
270            }
271
272            // wsa:FaultTo
273            // add if it doesn't already exist and OneWayFeature requests a specific FaultTo
274            if (headers.get(av.faultToTag, false) == null) {
275                WSEndpointReference faultToEpr = oneWayFeature.getFaultTo();
276                if (faultToEpr != null) {
277                    headers.add(faultToEpr.createHeader(av.faultToTag));
278                    // add wsa:MessageID only for non-null FaultTo
279                    if (headers.get(av.messageIDTag, false) == null) {
280                        headers.add(new StringHeader(av.messageIDTag, Message.generateMessageID()));
281                  }
282                }
283            }
284
285            // wsa:From
286            if (oneWayFeature.getFrom() != null) {
287                headers.addOrReplace(oneWayFeature.getFrom().createHeader(av.fromTag));
288            }
289
290            // wsa:RelatesTo
291            if (oneWayFeature.getRelatesToID() != null) {
292                headers.addOrReplace(new RelatesToHeader(av.relatesToTag, oneWayFeature.getRelatesToID()));
293            }
294        }
295    }
296
297    /**
298     * Creates wsa:To, wsa:Action and wsa:MessageID header on the client
299     *
300     * @param packet request packet
301     * @param av WS-Addressing version
302     * @param sv SOAP version
303     * @param action Action Message Addressing Property value
304     * @throws IllegalArgumentException if any of the parameters is null.
305     */
306    private static void fillCommonAddressingHeaders(MessageHeaders headers, Packet packet, @NotNull AddressingVersion av, @NotNull SOAPVersion sv, @NotNull String action, boolean mustUnderstand) {
307        if (packet == null) {
308            throw new IllegalArgumentException(AddressingMessages.NULL_PACKET());
309        }
310
311        if (av == null) {
312            throw new IllegalArgumentException(AddressingMessages.NULL_ADDRESSING_VERSION());
313        }
314
315        if (sv == null) {
316            throw new IllegalArgumentException(AddressingMessages.NULL_SOAP_VERSION());
317        }
318
319        if (action == null && !sv.httpBindingId.equals(SOAPBinding.SOAP12HTTP_BINDING)) {
320            throw new IllegalArgumentException(AddressingMessages.NULL_ACTION());
321        }
322
323        // wsa:To
324        if (headers.get(av.toTag, false) == null) {
325          StringHeader h = new StringHeader(av.toTag, packet.endpointAddress.toString());
326          headers.add(h);
327        }
328
329        // wsa:Action
330        if (action != null) {
331            packet.soapAction = action;
332            if (headers.get(av.actionTag, false) == null) {
333                //As per WS-I BP 1.2/2.0, if one of the WSA headers is MU, then all WSA headers should be treated as MU.,
334                // so just set MU on action header
335              StringHeader h = new StringHeader(av.actionTag, action, sv, mustUnderstand);
336              headers.add(h);
337            }
338        }
339    }
340
341
342}
343