src/share/jaxws_classes/com/sun/xml/internal/ws/addressing/WsaServerTube.java

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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
26 package com.sun.xml.internal.ws.addressing;
27
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.ws.addressing.model.ActionNotSupportedException;
31 import com.sun.xml.internal.ws.addressing.model.InvalidAddressingHeaderException;
32 import com.sun.xml.internal.ws.api.EndpointAddress;
33 import com.sun.xml.internal.ws.api.SOAPVersion;
34 import com.sun.xml.internal.ws.api.WSBinding;
35 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
36 import com.sun.xml.internal.ws.api.addressing.NonAnonymousResponseProcessor;
37 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
38 import com.sun.xml.internal.ws.api.message.AddressingUtils;
39 import com.sun.xml.internal.ws.api.message.Message;
40 import com.sun.xml.internal.ws.api.message.MessageHeaders;
41 import com.sun.xml.internal.ws.api.message.Messages;
42 import com.sun.xml.internal.ws.api.message.Packet;
43 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
44 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
45 import com.sun.xml.internal.ws.api.pipe.*;
46 import com.sun.xml.internal.ws.api.server.WSEndpoint;
47 import com.sun.xml.internal.ws.client.Stub;
48 import com.sun.xml.internal.ws.developer.JAXWSProperties;
49 import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
50 import com.sun.xml.internal.ws.message.FaultDetailHeader;
51 import com.sun.xml.internal.ws.resources.AddressingMessages;
52
53 import javax.xml.soap.SOAPFault;
54 import javax.xml.ws.WebServiceException;
55 import java.net.URI;
56 import java.util.logging.Level;
57 import java.util.logging.Logger;
58
59 /**
60 * Handles WS-Addressing for the server.
61 *
62 * @author Rama Pulavarthi
63 * @author Kohsuke Kawaguchi
64 * @author Arun Gupta
65 */
66 public class WsaServerTube extends WsaTube {
67 private WSEndpoint endpoint;
68 // store the replyTo/faultTo of the message currently being processed.
69 // both will be set to non-null in processRequest
70 private WSEndpointReference replyTo;
71 private WSEndpointReference faultTo;
72 private boolean isAnonymousRequired = false;
73 // Used by subclasses to avoid this class closing the transport back
74 // channel based on the ReplyTo/FaultTo addrs being non-anonymous. False
75 // can be useful in cases where special back-channel handling is required.
76 protected boolean isEarlyBackchannelCloseAllowed = true;
77
78 /**
79 * WSDLBoundOperation calculated on the Request payload.
80 * Used for determining ReplyTo or Fault Action for non-anonymous responses *
81 */
82 private WSDLBoundOperation wbo;
83 public WsaServerTube(WSEndpoint endpoint, @NotNull WSDLPort wsdlPort, WSBinding binding, Tube next) {
84 super(wsdlPort, binding, next);
85 this.endpoint = endpoint;
86 }
87
88 public WsaServerTube(WsaServerTube that, TubeCloner cloner) {
89 super(that, cloner);
90 endpoint = that.endpoint;
91 }
92
93 @Override
94 public WsaServerTube copy(TubeCloner cloner) {
95 return new WsaServerTube(this, cloner);
96 }
97
98 @Override
99 public @NotNull NextAction processRequest(Packet request) {
100 Message msg = request.getMessage();
101 if (msg == null) {
102 return doInvoke(next,request);
103 } // hmm?
104
105 // expose bunch of addressing related properties for advanced applications
106 request.addSatellite(new WsaPropertyBag(addressingVersion,soapVersion,request));
107
108 // Store request ReplyTo and FaultTo in requestPacket.invocationProperties
109 // so that they can be used after responsePacket is received.
110 // These properties are used if a fault is thrown from the subsequent Pipe/Tubes.
111
112 MessageHeaders hl = request.getMessage().getHeaders();
113 String msgId;
114 try {
115 replyTo = AddressingUtils.getReplyTo(hl, addressingVersion, soapVersion);
116 faultTo = AddressingUtils.getFaultTo(hl, addressingVersion, soapVersion);
117 msgId = AddressingUtils.getMessageID(hl, addressingVersion, soapVersion);
118 } catch (InvalidAddressingHeaderException e) {
119
120 LOGGER.log(Level.WARNING, addressingVersion.getInvalidMapText()+", Problem header:" + e.getProblemHeader()+ ", Reason: "+ e.getSubsubcode(),e);
121
122 // problematic header must be removed since it can fail during Fault message processing
123 hl.remove(e.getProblemHeader());
124
125 SOAPFault soapFault = helper.createInvalidAddressingHeaderFault(e, addressingVersion);
126 // WS-A fault processing for one-way methods
127 if ((wsdlPort!=null) && request.getMessage().isOneWay(wsdlPort)) {
128 Packet response = request.createServerResponse(null, wsdlPort, null, binding);
129 return doReturnWith(response);
130 }
131
132 Message m = Messages.create(soapFault);
133 if (soapVersion == SOAPVersion.SOAP_11) {
134 FaultDetailHeader s11FaultDetailHeader = new FaultDetailHeader(addressingVersion, addressingVersion.problemHeaderQNameTag.getLocalPart(), e.getProblemHeader());
135 m.getHeaders().add(s11FaultDetailHeader);
136 }
137
138 Packet response = request.createServerResponse(m, wsdlPort, null, binding);
139 return doReturnWith(response);
140 }
141
142 // defaulting
143 if (replyTo == null) {
144 replyTo = addressingVersion.anonymousEpr;
145 }
146 if (faultTo == null) {
147 faultTo = replyTo;
148 }
149
150 // Save a copy into the packet such that we can save it with that
151 // packet if we're going to deliver the response at a later time
152 // (async from the request).
153 request.put(WsaPropertyBag.WSA_REPLYTO_FROM_REQUEST, replyTo);
154 request.put(WsaPropertyBag.WSA_FAULTTO_FROM_REQUEST, faultTo);
155 request.put(WsaPropertyBag.WSA_MSGID_FROM_REQUEST, msgId);
156
157 wbo = getWSDLBoundOperation(request);
158 isAnonymousRequired = isAnonymousRequired(wbo);
159
160 Packet p = validateInboundHeaders(request);
161 // if one-way message and WS-A header processing fault has occurred,
162 // then do no further processing
163 if (p.getMessage() == null) {
164 return doReturnWith(p);
165 }
166
167 // if we find an error in addressing header, just turn around the direction here
168 if (p.getMessage().isFault()) {
169 // close the transportBackChannel if we know that
170 // we'll never use them
171 if (isEarlyBackchannelCloseAllowed &&
172 !(isAnonymousRequired) &&
173 !faultTo.isAnonymous() && request.transportBackChannel != null) {
174 request.transportBackChannel.close();
175 }
176 return processResponse(p);
177 }
178 // close the transportBackChannel if we know that
179 // we'll never use them
180 if (isEarlyBackchannelCloseAllowed &&
181 !(isAnonymousRequired) &&
182 !replyTo.isAnonymous() && !faultTo.isAnonymous() &&
183 request.transportBackChannel != null) {
184 request.transportBackChannel.close();
185 }
186 return doInvoke(next,p);
187 }
188
189 protected boolean isAnonymousRequired(@Nullable WSDLBoundOperation wbo) {
190 //this requirement can only be specified in W3C case, Override this in W3C case.
191 return false;
192 }
193
194 protected void checkAnonymousSemantics(WSDLBoundOperation wbo, WSEndpointReference replyTo, WSEndpointReference faultTo) {
195 //this requirement can only be specified in W3C case, Override this in W3C case.
196 }
197
198 @Override
199 public @NotNull NextAction processException(Throwable t) {
200 final Packet response = Fiber.current().getPacket();
201 ThrowableContainerPropertySet tc = response.getSatellite(ThrowableContainerPropertySet.class);
202 if (tc == null) {
203 tc = new ThrowableContainerPropertySet(t);
204 response.addSatellite(tc);
205 } else if (t != tc.getThrowable()) {
206 // This is a pathological case where an exception happens after a previous exception.
207 // Make sure you report the latest one.
208 tc.setThrowable(t);
209 }
210 return processResponse(response.endpoint.createServiceResponseForException(tc, response, soapVersion, wsdlPort,
211 response.endpoint.getSEIModel(),
212 binding));
213 }
214
215 @Override
216 public @NotNull NextAction processResponse(Packet response) {
217 Message msg = response.getMessage();
218 if (msg ==null) {
219 return doReturnWith(response);
220 } // one way message. Nothing to see here. Move on.
221
222 String to = AddressingUtils.getTo(msg.getHeaders(),
223 addressingVersion, soapVersion);
224 if (to != null) {
225 replyTo = faultTo = new WSEndpointReference(to, addressingVersion);
226 }
227
228 if (replyTo == null) {
229 // This is an async response or we're not processing the response in
230 // the same tube instance as we processed the request. Get the ReplyTo
231 // now, from the properties we stored into the request packet. We
232 // assume anyone that interrupted the request->response flow will have
233 // saved the ReplyTo and put it back into the packet for our use.
234 replyTo = (WSEndpointReference)response.
235 get(WsaPropertyBag.WSA_REPLYTO_FROM_REQUEST);
236 }
237
238 if (faultTo == null) {
239 // This is an async response or we're not processing the response in
240 // the same tube instance as we processed the request. Get the FaultTo
241 // now, from the properties we stored into the request packet. We
242 // assume anyone that interrupted the request->response flow will have
243 // saved the FaultTo and put it back into the packet for our use.
244 faultTo = (WSEndpointReference)response.
245 get(WsaPropertyBag.WSA_FAULTTO_FROM_REQUEST);
246 }
247
248 WSEndpointReference target = msg.isFault() ? faultTo : replyTo;
249 if (target == null && response.proxy instanceof Stub) {
250 target = ((Stub) response.proxy).getWSEndpointReference();
251 }
252 if (target == null || target.isAnonymous() || isAnonymousRequired) {
253 return doReturnWith(response);
254 }
255 if (target.isNone()) {
256 // the caller doesn't want to hear about it, so proceed like one-way
257 response.setMessage(null);
258 return doReturnWith(response);
259 }
260
261 if ((wsdlPort!=null) && response.getMessage().isOneWay(wsdlPort)) {
262 // one way message but with replyTo. I believe this is a hack for WS-TX - KK.
263 LOGGER.fine(AddressingMessages.NON_ANONYMOUS_RESPONSE_ONEWAY());
264 return doReturnWith(response);
265 }
266
267 // MTU: If we're not sending a response that corresponds to a WSDL op,
268 // then take whatever soapAction is set on the packet (as allowing
269 // helper.getOutputAction() will only result in a bogus 'unset'
270 // action value.
271 if (wbo != null || response.soapAction == null) {
272 String action = response.getMessage().isFault() ?
273 helper.getFaultAction(wbo, response) :
274 helper.getOutputAction(wbo);
275 //set the SOAPAction, as its got to be same as wsa:Action
276 if (response.soapAction == null ||
277 (action != null &&
278 !action.equals(AddressingVersion.UNSET_OUTPUT_ACTION))) {
279 response.soapAction = action;
280 }
281 }
282 response.expectReply = false;
283
284 EndpointAddress adrs;
285 try {
286 adrs = new EndpointAddress(URI.create(target.getAddress()));
287 } catch (NullPointerException e) {
288 throw new WebServiceException(e);
289 } catch (IllegalArgumentException e) {
290 throw new WebServiceException(e);
291 }
292
293 response.endpointAddress = adrs;
294
295 if (response.isAdapterDeliversNonAnonymousResponse) {
296 return doReturnWith(response);
297 }
298
299 return doReturnWith(NonAnonymousResponseProcessor.getDefault().process(response));
300 }
301
302 @Override
303 protected void validateAction(Packet packet) {
304 //There may not be a WSDL operation. There may not even be a WSDL.
305 //For instance this may be a RM CreateSequence message.
306 WSDLBoundOperation wsdlBoundOperation = getWSDLBoundOperation(packet);
307
308 if (wsdlBoundOperation == null) {
309 return;
310 }
311
312 String gotA = AddressingUtils.getAction(
313 packet.getMessage().getHeaders(),
314 addressingVersion, soapVersion);
315
316 if (gotA == null) {
317 throw new WebServiceException(AddressingMessages.VALIDATION_SERVER_NULL_ACTION());
318 }
319
320 String expected = helper.getInputAction(packet);
321 String soapAction = helper.getSOAPAction(packet);
322 if (helper.isInputActionDefault(packet) && (soapAction != null && !soapAction.equals(""))) {
323 expected = soapAction;
324 }
325
326 if (expected != null && !gotA.equals(expected)) {
327 throw new ActionNotSupportedException(gotA);
328 }
329 }
330
331 @Override
332 protected void checkMessageAddressingProperties(Packet packet) {
333 super.checkMessageAddressingProperties(packet);
334
335 // wsaw:Anonymous validation
336 WSDLBoundOperation wsdlBoundOperation = getWSDLBoundOperation(packet);
337 checkAnonymousSemantics(wsdlBoundOperation, replyTo, faultTo);
338 // check if addresses are valid
339 checkNonAnonymousAddresses(replyTo,faultTo);
340 }
341
342 @SuppressWarnings("ResultOfObjectAllocationIgnored")
343 private void checkNonAnonymousAddresses(WSEndpointReference replyTo, WSEndpointReference faultTo) {
344 if (!replyTo.isAnonymous()) {
345 try {
346 new EndpointAddress(URI.create(replyTo.getAddress()));
347 } catch (Exception e) {
348 throw new InvalidAddressingHeaderException(addressingVersion.replyToTag, addressingVersion.invalidAddressTag);
349 }
350 }
351 //for now only validate ReplyTo
352 /*
353 if (!faultTo.isAnonymous()) {
354 try {
355 new EndpointAddress(URI.create(faultTo.getAddress()));
356 } catch (IllegalArgumentException e) {
357 throw new InvalidAddressingHeaderException(addressingVersion.faultToTag, addressingVersion.invalidAddressTag);
358 }
359 }
360 */
361
362 }
363
364 /**
365 * @deprecated
366 * Use {@link JAXWSProperties#ADDRESSING_MESSAGEID}.
367 */
368 public static final String REQUEST_MESSAGE_ID = "com.sun.xml.internal.ws.addressing.request.messageID";
369
370 private static final Logger LOGGER = Logger.getLogger(WsaServerTube.class.getName());
371 }

mercurial