Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.ws.client.dispatch;
28 import com.sun.istack.internal.NotNull;
29 import com.sun.istack.internal.Nullable;
30 import com.sun.xml.internal.ws.api.BindingID;
31 import com.sun.xml.internal.ws.api.SOAPVersion;
32 import com.sun.xml.internal.ws.api.WSBinding;
33 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
34 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
35 import com.sun.xml.internal.ws.api.client.WSPortInfo;
36 import com.sun.xml.internal.ws.api.message.AddressingUtils;
37 import com.sun.xml.internal.ws.api.message.Attachment;
38 import com.sun.xml.internal.ws.api.message.AttachmentSet;
39 import com.sun.xml.internal.ws.api.message.Message;
40 import com.sun.xml.internal.ws.api.message.Packet;
41 import com.sun.xml.internal.ws.api.pipe.Fiber;
42 import com.sun.xml.internal.ws.api.pipe.Tube;
43 import com.sun.xml.internal.ws.api.server.Container;
44 import com.sun.xml.internal.ws.api.server.ContainerResolver;
45 import com.sun.xml.internal.ws.binding.BindingImpl;
46 import com.sun.xml.internal.ws.client.*;
47 import com.sun.xml.internal.ws.encoding.soap.DeserializationException;
48 import com.sun.xml.internal.ws.fault.SOAPFaultBuilder;
49 import com.sun.xml.internal.ws.message.AttachmentSetImpl;
50 import com.sun.xml.internal.ws.message.DataHandlerAttachment;
51 import com.sun.xml.internal.ws.resources.DispatchMessages;
53 import javax.activation.DataHandler;
54 import javax.xml.bind.JAXBException;
55 import javax.xml.namespace.QName;
56 import javax.xml.transform.Source;
57 import javax.xml.ws.AsyncHandler;
58 import javax.xml.ws.BindingProvider;
59 import javax.xml.ws.Dispatch;
60 import javax.xml.ws.Response;
61 import javax.xml.ws.Service;
62 import javax.xml.ws.Service.Mode;
63 import javax.xml.ws.WebServiceException;
64 import javax.xml.ws.handler.MessageContext;
65 import javax.xml.ws.http.HTTPBinding;
66 import javax.xml.ws.soap.SOAPBinding;
67 import javax.xml.ws.soap.SOAPFaultException;
68 import java.net.MalformedURLException;
69 import java.net.URI;
70 import java.net.URISyntaxException;
71 import java.net.URL;
72 import java.util.ArrayList;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.concurrent.Callable;
77 import java.util.concurrent.Future;
78 import java.util.logging.Level;
79 import java.util.logging.Logger;
82 /**
83 * The <code>DispatchImpl</code> abstract class provides support
84 * for the dynamic invocation of a service endpoint operation using XML
85 * constructs, JAXB objects or <code>SOAPMessage</code>. The <code>javax.xml.ws.Service</code>
86 * interface acts as a factory for the creation of <code>DispatchImpl</code>
87 * instances.
88 *
89 * @author WS Development Team
90 * @version 1.0
91 */
92 public abstract class DispatchImpl<T> extends Stub implements Dispatch<T> {
94 private static final Logger LOGGER = Logger.getLogger(DispatchImpl.class.getName());
96 final Service.Mode mode;
97 final SOAPVersion soapVersion;
98 final boolean allowFaultResponseMsg;
99 static final long AWAIT_TERMINATION_TIME = 800L;
101 /**
102 *
103 * @param port dispatch instance is associated with this wsdl port qName
104 * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD
105 * @param owner Service that created the Dispatch
106 * @param pipe Master pipe for the pipeline
107 * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP
108 */
109 @Deprecated
110 protected DispatchImpl(QName port, Service.Mode mode, WSServiceDelegate owner, Tube pipe, BindingImpl binding, @Nullable WSEndpointReference epr) {
111 super(port, owner, pipe, binding, (owner.getWsdlService() != null)? owner.getWsdlService().get(port) : null , owner.getEndpointAddress(port), epr);
112 this.mode = mode;
113 this.soapVersion = binding.getSOAPVersion();
114 this.allowFaultResponseMsg = false;
115 }
117 /**
118 * @param portInfo dispatch instance is associated with this portInfo
119 * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD
120 * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP
121 */
122 protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, @Nullable WSEndpointReference epr) {
123 this(portInfo, mode, binding, epr, false);
124 }
126 /**
127 * @param portInfo dispatch instance is associated with this portInfo
128 * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD
129 * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP
130 * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance.
131 */
132 protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) {
133 this(portInfo, mode, binding, null, epr, allowFaultResponseMsg);
134 }
136 /**
137 * @param portInfo dispatch instance is associated with this portInfo
138 * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD
139 * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP
140 * @param pipe Master pipe for the pipeline
141 * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance.
142 */
143 protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, Tube pipe, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) {
144 super(portInfo, binding, pipe, portInfo.getEndpointAddress(), epr);
145 this.mode = mode;
146 this.soapVersion = binding.getSOAPVersion();
147 this.allowFaultResponseMsg = allowFaultResponseMsg;
148 }
149 /**
150 *
151 * @param portportInfo dispatch instance is associated with this wsdl port qName
152 * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD
153 * @param pipe Master pipe for the pipeline
154 * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP
155 * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance.
156 */
157 protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, Tube pipe, BindingImpl binding, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) {
158 super(portInfo, binding, pipe, portInfo.getEndpointAddress(), epr);
159 this.mode = mode;
160 this.soapVersion = binding.getSOAPVersion();
161 this.allowFaultResponseMsg = allowFaultResponseMsg;
162 }
164 /**
165 * Abstract method that is implemented by each concrete Dispatch class
166 * @param msg message passed in from the client program on the invocation
167 * @return The Message created returned as the Interface in actuallity a
168 * concrete Message Type
169 */
170 abstract Packet createPacket(T msg);
172 /**
173 * Obtains the value to return from the response message.
174 */
175 abstract T toReturnValue(Packet response);
177 public final Response<T> invokeAsync(T param) {
178 Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
179 try {
180 if (LOGGER.isLoggable(Level.FINE)) {
181 dumpParam(param, "invokeAsync(T)");
182 }
183 AsyncInvoker invoker = new DispatchAsyncInvoker(param);
184 AsyncResponseImpl<T> ft = new AsyncResponseImpl<T>(invoker,null);
185 invoker.setReceiver(ft);
186 ft.run();
187 return ft;
188 } finally {
189 ContainerResolver.getDefault().exitContainer(old);
190 }
191 }
193 private void dumpParam(T param, String method) {
194 if (param instanceof Packet) {
195 Packet message = (Packet)param;
197 String action;
198 String msgId;
199 if (LOGGER.isLoggable(Level.FINE)) {
200 AddressingVersion av = DispatchImpl.this.getBinding().getAddressingVersion();
201 SOAPVersion sv = DispatchImpl.this.getBinding().getSOAPVersion();
202 action =
203 av != null && message.getMessage() != null ?
204 AddressingUtils.getAction(message.getMessage().getHeaders(), av, sv) : null;
205 msgId =
206 av != null && message.getMessage() != null ?
207 AddressingUtils.getMessageID(message.getMessage().getHeaders(), av, sv) : null;
208 LOGGER.fine("In DispatchImpl." + method + " for message with action: " + action + " and msg ID: " + msgId + " msg: " + message.getMessage());
210 if (message.getMessage() == null) {
211 LOGGER.fine("Dispatching null message for action: " + action + " and msg ID: " + msgId);
212 }
213 }
214 }
215 }
216 public final Future<?> invokeAsync(T param, AsyncHandler<T> asyncHandler) {
217 Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
218 try {
219 if (LOGGER.isLoggable(Level.FINE)) {
220 dumpParam(param, "invokeAsync(T, AsyncHandler<T>)");
221 }
222 AsyncInvoker invoker = new DispatchAsyncInvoker(param);
223 AsyncResponseImpl<T> ft = new AsyncResponseImpl<T>(invoker,asyncHandler);
224 invoker.setReceiver(ft);
225 invoker.setNonNullAsyncHandlerGiven(asyncHandler != null);
227 ft.run();
228 return ft;
229 } finally {
230 ContainerResolver.getDefault().exitContainer(old);
231 }
232 }
234 /**
235 * Synchronously invokes a service.
236 *
237 * See {@link #process(Packet, RequestContext, ResponseContextReceiver)} on
238 * why it takes a {@link RequestContext} and {@link ResponseContextReceiver} as a parameter.
239 */
240 public final T doInvoke(T in, RequestContext rc, ResponseContextReceiver receiver){
241 Packet response = null;
242 try {
243 try {
244 checkNullAllowed(in, rc, binding, mode);
246 Packet message = createPacket(in);
247 message.setState(Packet.State.ClientRequest);
248 resolveEndpointAddress(message, rc);
249 setProperties(message,true);
250 response = process(message,rc,receiver);
251 Message msg = response.getMessage();
253 // REVIEW: eliminate allowFaultResponseMsg, but make that behavior default for MessageDispatch, PacketDispatch
254 if(msg != null && msg.isFault() &&
255 !allowFaultResponseMsg) {
256 SOAPFaultBuilder faultBuilder = SOAPFaultBuilder.create(msg);
257 // passing null means there is no checked excpetion we're looking for all
258 // it will get back to us is a protocol exception
259 throw (SOAPFaultException)faultBuilder.createException(null);
260 }
261 } catch (JAXBException e) {
262 //TODO: i18nify
263 throw new DeserializationException(DispatchMessages.INVALID_RESPONSE_DESERIALIZATION(),e);
264 } catch(WebServiceException e){
265 //it could be a WebServiceException or a ProtocolException
266 throw e;
267 } catch(Throwable e){
268 // it could be a RuntimeException resulting due to some internal bug or
269 // its some other exception resulting from user error, wrap it in
270 // WebServiceException
271 throw new WebServiceException(e);
272 }
274 return toReturnValue(response);
275 } finally {
276 // REVIEW: Move to AsyncTransportProvider
277 if (response != null && response.transportBackChannel != null)
278 response.transportBackChannel.close();
279 }
280 }
282 public final T invoke(T in) {
283 Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
284 try {
285 if (LOGGER.isLoggable(Level.FINE)) {
286 dumpParam(in, "invoke(T)");
287 }
289 return doInvoke(in,requestContext,this);
290 } finally {
291 ContainerResolver.getDefault().exitContainer(old);
292 }
293 }
295 public final void invokeOneWay(T in) {
296 Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
297 try {
298 if (LOGGER.isLoggable(Level.FINE)) {
299 dumpParam(in, "invokeOneWay(T)");
300 }
302 try {
303 checkNullAllowed(in, requestContext, binding, mode);
305 Packet request = createPacket(in);
306 request.setState(Packet.State.ClientRequest);
307 setProperties(request,false);
308 process(request,requestContext,this);
309 } catch(WebServiceException e){
310 //it could be a WebServiceException or a ProtocolException
311 throw e;
312 } catch(Throwable e){
313 // it could be a RuntimeException resulting due to some internal bug or
314 // its some other exception resulting from user error, wrap it in
315 // WebServiceException
316 throw new WebServiceException(e);
317 }
318 } finally {
319 ContainerResolver.getDefault().exitContainer(old);
320 }
321 }
323 void setProperties(Packet packet, boolean expectReply) {
324 packet.expectReply = expectReply;
325 }
327 static boolean isXMLHttp(@NotNull WSBinding binding) {
328 return binding.getBindingId().equals(BindingID.XML_HTTP);
329 }
331 static boolean isPAYLOADMode(@NotNull Service.Mode mode) {
332 return mode == Service.Mode.PAYLOAD;
333 }
335 static void checkNullAllowed(@Nullable Object in, RequestContext rc, WSBinding binding, Service.Mode mode) {
337 if (in != null)
338 return;
340 //With HTTP Binding a null invocation parameter can not be used
341 //with HTTP Request Method == POST
342 if (isXMLHttp(binding)){
343 if (methodNotOk(rc))
344 throw new WebServiceException(DispatchMessages.INVALID_NULLARG_XMLHTTP_REQUEST_METHOD(HTTP_REQUEST_METHOD_POST, HTTP_REQUEST_METHOD_GET));
345 } else { //soapBinding
346 if (mode == Service.Mode.MESSAGE )
347 throw new WebServiceException(DispatchMessages.INVALID_NULLARG_SOAP_MSGMODE(mode.name(), Service.Mode.PAYLOAD.toString()));
348 }
349 }
351 static boolean methodNotOk(@NotNull RequestContext rc) {
352 String requestMethod = (String)rc.get(MessageContext.HTTP_REQUEST_METHOD);
353 String request = (requestMethod == null)? HTTP_REQUEST_METHOD_POST: requestMethod;
354 // if method == post or put with a null invocation parameter in xml/http binding this is not ok
355 return HTTP_REQUEST_METHOD_POST.equalsIgnoreCase(request) || HTTP_REQUEST_METHOD_PUT.equalsIgnoreCase(request);
356 }
358 public static void checkValidSOAPMessageDispatch(WSBinding binding, Service.Mode mode) {
359 // Dispatch<SOAPMessage> is only valid for soap binding and in Service.Mode.MESSAGE
360 if (DispatchImpl.isXMLHttp(binding))
361 throw new WebServiceException(DispatchMessages.INVALID_SOAPMESSAGE_DISPATCH_BINDING(HTTPBinding.HTTP_BINDING, SOAPBinding.SOAP11HTTP_BINDING + " or " + SOAPBinding.SOAP12HTTP_BINDING));
362 if (DispatchImpl.isPAYLOADMode(mode))
363 throw new WebServiceException(DispatchMessages.INVALID_SOAPMESSAGE_DISPATCH_MSGMODE(mode.name(), Service.Mode.MESSAGE.toString()));
364 }
366 public static void checkValidDataSourceDispatch(WSBinding binding, Service.Mode mode) {
367 // Dispatch<DataSource> is only valid with xml/http binding and in Service.Mode.MESSAGE
368 if (!DispatchImpl.isXMLHttp(binding))
369 throw new WebServiceException(DispatchMessages.INVALID_DATASOURCE_DISPATCH_BINDING("SOAP/HTTP", HTTPBinding.HTTP_BINDING));
370 if (DispatchImpl.isPAYLOADMode(mode))
371 throw new WebServiceException(DispatchMessages.INVALID_DATASOURCE_DISPATCH_MSGMODE(mode.name(), Service.Mode.MESSAGE.toString()));
372 }
374 public final @NotNull QName getPortName() {
375 return portname;
376 }
378 void resolveEndpointAddress(@NotNull final Packet message, @NotNull final RequestContext requestContext) {
379 final boolean p = message.packetTakesPriorityOverRequestContext;
381 //resolve endpoint look for query parameters, pathInfo
382 String endpoint;
383 if (p && message.endpointAddress != null) {
384 endpoint = message.endpointAddress.toString();
385 } else {
386 endpoint = (String) requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
387 }
388 // This is existing before packetTakesPriorityOverRequestContext so leaving in place.
389 if (endpoint == null) {
390 if (message.endpointAddress == null) throw new WebServiceException(DispatchMessages.INVALID_NULLARG_URI());
391 endpoint = message.endpointAddress.toString();
392 }
394 String pathInfo = null;
395 String queryString = null;
396 if (p && message.invocationProperties.get(MessageContext.PATH_INFO) != null) {
397 pathInfo = (String) message.invocationProperties.get(MessageContext.PATH_INFO);
398 } else if (requestContext.get(MessageContext.PATH_INFO) != null) {
399 pathInfo = (String) requestContext.get(MessageContext.PATH_INFO);
400 }
402 if (p && message.invocationProperties.get(MessageContext.QUERY_STRING) != null) {
403 queryString = (String) message.invocationProperties.get(MessageContext.QUERY_STRING);
404 } else if (requestContext.get(MessageContext.QUERY_STRING) != null) {
405 queryString = (String) requestContext.get(MessageContext.QUERY_STRING);
406 }
408 if (pathInfo != null || queryString != null) {
409 pathInfo = checkPath(pathInfo);
410 queryString = checkQuery(queryString);
411 if (endpoint != null) {
412 try {
413 final URI endpointURI = new URI(endpoint);
414 endpoint = resolveURI(endpointURI, pathInfo, queryString);
415 } catch (URISyntaxException e) {
416 throw new WebServiceException(DispatchMessages.INVALID_URI(endpoint));
417 }
418 }
419 }
420 // These two lines used to be inside the above if. It is outside so:
421 // - in cases where there is no setting of address on a Packet before invocation or no pathInfo/queryString
422 // this will just put back what it found in the requestContext - basically a noop.
423 // - but when info is in the Packet this will update so it will get used later.
424 // Remember - we are operating on a copied RequestContext at this point - not the sticky one in the Stub.
425 requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
426 // This is not necessary because a later step will copy the resolvedEndpoint put above into message.
427 //message.endpointAddress = EndpointAddress.create(endpoint);
428 }
430 protected @NotNull String resolveURI(@NotNull URI endpointURI, @Nullable String pathInfo, @Nullable String queryString) {
431 String query = null;
432 String fragment = null;
433 if (queryString != null) {
434 final URI result;
435 try {
436 URI tp = new URI(null, null, endpointURI.getPath(), queryString, null);
437 result = endpointURI.resolve(tp);
438 } catch (URISyntaxException e) {
439 throw new WebServiceException(DispatchMessages.INVALID_QUERY_STRING(queryString));
440 }
441 query = result.getQuery();
442 fragment = result.getFragment();
443 }
445 final String path = (pathInfo != null) ? pathInfo : endpointURI.getPath();
446 try {
447 //final URI temp = new URI(null, null, path, query, fragment);
448 //return endpointURI.resolve(temp).toURL().toExternalForm();
449 // Using the following HACK instead of the above to avoid double encoding of
450 // the query. Application's QUERY_STRING is encoded using URLEncoder.encode().
451 // If we use that query in URI's constructor, it is encoded again.
452 // URLEncoder's encoding is not the same as URI's encoding of the query.
453 // See {@link URL}
454 StringBuilder spec = new StringBuilder();
455 if (path != null) {
456 spec.append(path);
457 }
458 if (query != null) {
459 spec.append("?");
460 spec.append(query);
461 }
462 if (fragment != null) {
463 spec.append("#");
464 spec.append(fragment);
465 }
466 return new URL(endpointURI.toURL(), spec.toString()).toExternalForm();
467 } catch (MalformedURLException e) {
468 throw new WebServiceException(DispatchMessages.INVALID_URI_RESOLUTION(path));
469 }
470 }
472 private static String checkPath(@Nullable String path) {
473 //does it begin with /
474 return (path == null || path.startsWith("/")) ? path : "/" + path;
475 }
477 private static String checkQuery(@Nullable String query) {
478 if (query == null) return null;
480 if (query.indexOf('?') == 0)
481 throw new WebServiceException(DispatchMessages.INVALID_QUERY_LEADING_CHAR(query));
482 return query;
483 }
486 protected AttachmentSet setOutboundAttachments() {
487 HashMap<String, DataHandler> attachments = (HashMap<String, DataHandler>)
488 getRequestContext().get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS);
490 if (attachments != null) {
491 List<Attachment> alist = new ArrayList();
492 for (Map.Entry<String, DataHandler> att : attachments.entrySet()) {
493 DataHandlerAttachment dha = new DataHandlerAttachment(att.getKey(), att.getValue());
494 alist.add(dha);
495 }
496 return new AttachmentSetImpl(alist);
497 }
498 return new AttachmentSetImpl();
499 }
501 /* private void getInboundAttachments(Message msg) {
502 AttachmentSet attachments = msg.getAttachments();
503 if (!attachments.isEmpty()) {
504 Map<String, DataHandler> in = new HashMap<String, DataHandler>();
505 for (Attachment attachment : attachments)
506 in.put(attachment.getContentId(), attachment.asDataHandler());
507 getResponseContext().put(MessageContext.INBOUND_MESSAGE_ATTACHMENTS, in);
508 }
510 }
511 */
514 /**
515 * Calls {@link DispatchImpl#doInvoke(Object,RequestContext,ResponseContextReceiver)}.
516 */
517 private class Invoker implements Callable {
518 private final T param;
519 // snapshot the context now. this is necessary to avoid concurrency issue,
520 // and is required by the spec
521 private final RequestContext rc = requestContext.copy();
523 /**
524 * Because of the object instantiation order,
525 * we can't take this as a constructor parameter.
526 */
527 private ResponseContextReceiver receiver;
529 Invoker(T param) {
530 this.param = param;
531 }
533 public T call() throws Exception {
534 if (LOGGER.isLoggable(Level.FINE)) {
535 dumpParam(param, "call()");
536 }
537 return doInvoke(param,rc,receiver);
538 }
540 void setReceiver(ResponseContextReceiver receiver) {
541 this.receiver = receiver;
542 }
543 }
545 /**
546 *
547 */
548 private class DispatchAsyncInvoker extends AsyncInvoker {
549 private final T param;
550 // snapshot the context now. this is necessary to avoid concurrency issue,
551 // and is required by the spec
552 private final RequestContext rc = requestContext.copy();
554 DispatchAsyncInvoker(T param) {
555 this.param = param;
556 }
558 public void do_run () {
559 checkNullAllowed(param, rc, binding, mode);
560 final Packet message = createPacket(param);
561 message.setState(Packet.State.ClientRequest);
562 message.nonNullAsyncHandlerGiven = this.nonNullAsyncHandlerGiven;
563 resolveEndpointAddress(message, rc);
564 setProperties(message,true);
566 String action = null;
567 String msgId = null;
568 if (LOGGER.isLoggable(Level.FINE)) {
569 AddressingVersion av = DispatchImpl.this.getBinding().getAddressingVersion();
570 SOAPVersion sv = DispatchImpl.this.getBinding().getSOAPVersion();
571 action =
572 av != null && message.getMessage() != null ?
573 AddressingUtils.getAction(message.getMessage().getHeaders(), av, sv) : null;
574 msgId =
575 av != null&& message.getMessage() != null ?
576 AddressingUtils.getMessageID(message.getMessage().getHeaders(), av, sv) : null;
577 LOGGER.fine("In DispatchAsyncInvoker.do_run for async message with action: " + action + " and msg ID: " + msgId);
578 }
580 final String actionUse = action;
581 final String msgIdUse = msgId;
583 Fiber.CompletionCallback callback = new Fiber.CompletionCallback() {
584 public void onCompletion(@NotNull Packet response) {
586 if (LOGGER.isLoggable(Level.FINE)) {
587 LOGGER.fine("Done with processAsync in DispatchAsyncInvoker.do_run, and setting response for async message with action: " + actionUse + " and msg ID: " + msgIdUse);
588 }
590 Message msg = response.getMessage();
592 if (LOGGER.isLoggable(Level.FINE)) {
593 LOGGER.fine("Done with processAsync in DispatchAsyncInvoker.do_run, and setting response for async message with action: " + actionUse + " and msg ID: " + msgIdUse + " msg: " + msg);
594 }
596 try {
597 if(msg != null && msg.isFault() &&
598 !allowFaultResponseMsg) {
599 SOAPFaultBuilder faultBuilder = SOAPFaultBuilder.create(msg);
600 // passing null means there is no checked excpetion we're looking for all
601 // it will get back to us is a protocol exception
602 throw (SOAPFaultException)faultBuilder.createException(null);
603 }
604 responseImpl.setResponseContext(new ResponseContext(response));
605 responseImpl.set(toReturnValue(response), null);
606 } catch (JAXBException e) {
607 //TODO: i18nify
608 responseImpl.set(null, new DeserializationException(DispatchMessages.INVALID_RESPONSE_DESERIALIZATION(),e));
609 } catch(WebServiceException e){
610 //it could be a WebServiceException or a ProtocolException
611 responseImpl.set(null, e);
612 } catch(Throwable e){
613 // It could be any RuntimeException resulting due to some internal bug.
614 // or its some other exception resulting from user error, wrap it in
615 // WebServiceException
616 responseImpl.set(null, new WebServiceException(e));
617 }
618 }
619 public void onCompletion(@NotNull Throwable error) {
620 if (LOGGER.isLoggable(Level.FINE)) {
621 LOGGER.fine("Done with processAsync in DispatchAsyncInvoker.do_run, and setting response for async message with action: " + actionUse + " and msg ID: " + msgIdUse + " Throwable: " + error.toString());
622 }
623 if (error instanceof WebServiceException) {
624 responseImpl.set(null, error);
626 } else {
627 //its RuntimeException or some other exception resulting from user error, wrap it in
628 // WebServiceException
629 responseImpl.set(null, new WebServiceException(error));
630 }
631 }
632 };
633 processAsync(responseImpl,message,rc, callback);
634 }
635 }
637 public void setOutboundHeaders(Object... headers) {
638 throw new UnsupportedOperationException();
639 }
641 static final String HTTP_REQUEST_METHOD_GET="GET";
642 static final String HTTP_REQUEST_METHOD_POST="POST";
643 static final String HTTP_REQUEST_METHOD_PUT="PUT";
645 @Deprecated
646 public static Dispatch<Source> createSourceDispatch(QName port, Mode mode, WSServiceDelegate owner, Tube pipe, BindingImpl binding, WSEndpointReference epr) {
647 if(isXMLHttp(binding))
648 return new RESTSourceDispatch(port,mode,owner,pipe,binding,epr);
649 else
650 return new SOAPSourceDispatch(port,mode,owner,pipe,binding,epr);
651 }
653 public static Dispatch<Source> createSourceDispatch(WSPortInfo portInfo, Mode mode, BindingImpl binding, WSEndpointReference epr) {
654 if (isXMLHttp(binding))
655 return new RESTSourceDispatch(portInfo, mode, binding, epr);
656 else
657 return new SOAPSourceDispatch(portInfo, mode, binding, epr);
658 }
659 }