src/share/jaxws_classes/com/sun/xml/internal/ws/client/dispatch/DispatchImpl.java

Fri, 04 Oct 2013 16:21:34 +0100

author
mkos
date
Fri, 04 Oct 2013 16:21:34 +0100
changeset 408
b0610cd08440
parent 384
8f2986ff0235
child 637
9c07ef4934dd
permissions
-rw-r--r--

8025054: Update JAX-WS RI integration to 2.2.9-b130926.1035
Reviewed-by: chegar

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

mercurial