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

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 384
8f2986ff0235
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

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

mercurial