1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/client/dispatch/DispatchImpl.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,659 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.ws.client.dispatch; 1.30 + 1.31 +import com.sun.istack.internal.NotNull; 1.32 +import com.sun.istack.internal.Nullable; 1.33 +import com.sun.xml.internal.ws.api.BindingID; 1.34 +import com.sun.xml.internal.ws.api.SOAPVersion; 1.35 +import com.sun.xml.internal.ws.api.WSBinding; 1.36 +import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 1.37 +import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; 1.38 +import com.sun.xml.internal.ws.api.client.WSPortInfo; 1.39 +import com.sun.xml.internal.ws.api.message.AddressingUtils; 1.40 +import com.sun.xml.internal.ws.api.message.Attachment; 1.41 +import com.sun.xml.internal.ws.api.message.AttachmentSet; 1.42 +import com.sun.xml.internal.ws.api.message.Message; 1.43 +import com.sun.xml.internal.ws.api.message.Packet; 1.44 +import com.sun.xml.internal.ws.api.pipe.Fiber; 1.45 +import com.sun.xml.internal.ws.api.pipe.Tube; 1.46 +import com.sun.xml.internal.ws.api.server.Container; 1.47 +import com.sun.xml.internal.ws.api.server.ContainerResolver; 1.48 +import com.sun.xml.internal.ws.binding.BindingImpl; 1.49 +import com.sun.xml.internal.ws.client.*; 1.50 +import com.sun.xml.internal.ws.encoding.soap.DeserializationException; 1.51 +import com.sun.xml.internal.ws.fault.SOAPFaultBuilder; 1.52 +import com.sun.xml.internal.ws.message.AttachmentSetImpl; 1.53 +import com.sun.xml.internal.ws.message.DataHandlerAttachment; 1.54 +import com.sun.xml.internal.ws.resources.DispatchMessages; 1.55 + 1.56 +import javax.activation.DataHandler; 1.57 +import javax.xml.bind.JAXBException; 1.58 +import javax.xml.namespace.QName; 1.59 +import javax.xml.transform.Source; 1.60 +import javax.xml.ws.AsyncHandler; 1.61 +import javax.xml.ws.BindingProvider; 1.62 +import javax.xml.ws.Dispatch; 1.63 +import javax.xml.ws.Response; 1.64 +import javax.xml.ws.Service; 1.65 +import javax.xml.ws.Service.Mode; 1.66 +import javax.xml.ws.WebServiceException; 1.67 +import javax.xml.ws.handler.MessageContext; 1.68 +import javax.xml.ws.http.HTTPBinding; 1.69 +import javax.xml.ws.soap.SOAPBinding; 1.70 +import javax.xml.ws.soap.SOAPFaultException; 1.71 +import java.net.MalformedURLException; 1.72 +import java.net.URI; 1.73 +import java.net.URISyntaxException; 1.74 +import java.net.URL; 1.75 +import java.util.ArrayList; 1.76 +import java.util.HashMap; 1.77 +import java.util.List; 1.78 +import java.util.Map; 1.79 +import java.util.concurrent.Callable; 1.80 +import java.util.concurrent.Future; 1.81 +import java.util.logging.Level; 1.82 +import java.util.logging.Logger; 1.83 + 1.84 + 1.85 +/** 1.86 + * The <code>DispatchImpl</code> abstract class provides support 1.87 + * for the dynamic invocation of a service endpoint operation using XML 1.88 + * constructs, JAXB objects or <code>SOAPMessage</code>. The <code>javax.xml.ws.Service</code> 1.89 + * interface acts as a factory for the creation of <code>DispatchImpl</code> 1.90 + * instances. 1.91 + * 1.92 + * @author WS Development Team 1.93 + * @version 1.0 1.94 + */ 1.95 +public abstract class DispatchImpl<T> extends Stub implements Dispatch<T> { 1.96 + 1.97 + private static final Logger LOGGER = Logger.getLogger(DispatchImpl.class.getName()); 1.98 + 1.99 + final Service.Mode mode; 1.100 + final SOAPVersion soapVersion; 1.101 + final boolean allowFaultResponseMsg; 1.102 + static final long AWAIT_TERMINATION_TIME = 800L; 1.103 + 1.104 + /** 1.105 + * 1.106 + * @param port dispatch instance is associated with this wsdl port qName 1.107 + * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD 1.108 + * @param owner Service that created the Dispatch 1.109 + * @param pipe Master pipe for the pipeline 1.110 + * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP 1.111 + */ 1.112 + @Deprecated 1.113 + protected DispatchImpl(QName port, Service.Mode mode, WSServiceDelegate owner, Tube pipe, BindingImpl binding, @Nullable WSEndpointReference epr) { 1.114 + super(port, owner, pipe, binding, (owner.getWsdlService() != null)? owner.getWsdlService().get(port) : null , owner.getEndpointAddress(port), epr); 1.115 + this.mode = mode; 1.116 + this.soapVersion = binding.getSOAPVersion(); 1.117 + this.allowFaultResponseMsg = false; 1.118 + } 1.119 + 1.120 + /** 1.121 + * @param portInfo dispatch instance is associated with this portInfo 1.122 + * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD 1.123 + * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP 1.124 + */ 1.125 + protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, @Nullable WSEndpointReference epr) { 1.126 + this(portInfo, mode, binding, epr, false); 1.127 + } 1.128 + 1.129 + /** 1.130 + * @param portInfo dispatch instance is associated with this portInfo 1.131 + * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD 1.132 + * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP 1.133 + * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance. 1.134 + */ 1.135 + protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) { 1.136 + this(portInfo, mode, binding, null, epr, allowFaultResponseMsg); 1.137 + } 1.138 + 1.139 + /** 1.140 + * @param portInfo dispatch instance is associated with this portInfo 1.141 + * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD 1.142 + * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP 1.143 + * @param pipe Master pipe for the pipeline 1.144 + * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance. 1.145 + */ 1.146 + protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, BindingImpl binding, Tube pipe, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) { 1.147 + super(portInfo, binding, pipe, portInfo.getEndpointAddress(), epr); 1.148 + this.mode = mode; 1.149 + this.soapVersion = binding.getSOAPVersion(); 1.150 + this.allowFaultResponseMsg = allowFaultResponseMsg; 1.151 + } 1.152 + /** 1.153 + * 1.154 + * @param portportInfo dispatch instance is associated with this wsdl port qName 1.155 + * @param mode Service.mode associated with this Dispatch instance - Service.mode.MESSAGE or Service.mode.PAYLOAD 1.156 + * @param pipe Master pipe for the pipeline 1.157 + * @param binding Binding of this Dispatch instance, current one of SOAP/HTTP or XML/HTTP 1.158 + * @param allowFaultResponseMsg A packet containing a SOAP fault message is allowed as the response to a request on this dispatch instance. 1.159 + */ 1.160 + protected DispatchImpl(WSPortInfo portInfo, Service.Mode mode, Tube pipe, BindingImpl binding, @Nullable WSEndpointReference epr, boolean allowFaultResponseMsg) { 1.161 + super(portInfo, binding, pipe, portInfo.getEndpointAddress(), epr); 1.162 + this.mode = mode; 1.163 + this.soapVersion = binding.getSOAPVersion(); 1.164 + this.allowFaultResponseMsg = allowFaultResponseMsg; 1.165 + } 1.166 + 1.167 + /** 1.168 + * Abstract method that is implemented by each concrete Dispatch class 1.169 + * @param msg message passed in from the client program on the invocation 1.170 + * @return The Message created returned as the Interface in actuallity a 1.171 + * concrete Message Type 1.172 + */ 1.173 + abstract Packet createPacket(T msg); 1.174 + 1.175 + /** 1.176 + * Obtains the value to return from the response message. 1.177 + */ 1.178 + abstract T toReturnValue(Packet response); 1.179 + 1.180 + public final Response<T> invokeAsync(T param) { 1.181 + Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); 1.182 + try { 1.183 + if (LOGGER.isLoggable(Level.FINE)) { 1.184 + dumpParam(param, "invokeAsync(T)"); 1.185 + } 1.186 + AsyncInvoker invoker = new DispatchAsyncInvoker(param); 1.187 + AsyncResponseImpl<T> ft = new AsyncResponseImpl<T>(invoker,null); 1.188 + invoker.setReceiver(ft); 1.189 + ft.run(); 1.190 + return ft; 1.191 + } finally { 1.192 + ContainerResolver.getDefault().exitContainer(old); 1.193 + } 1.194 + } 1.195 + 1.196 + private void dumpParam(T param, String method) { 1.197 + if (param instanceof Packet) { 1.198 + Packet message = (Packet)param; 1.199 + 1.200 + String action; 1.201 + String msgId; 1.202 + if (LOGGER.isLoggable(Level.FINE)) { 1.203 + AddressingVersion av = DispatchImpl.this.getBinding().getAddressingVersion(); 1.204 + SOAPVersion sv = DispatchImpl.this.getBinding().getSOAPVersion(); 1.205 + action = 1.206 + av != null && message.getMessage() != null ? 1.207 + AddressingUtils.getAction(message.getMessage().getHeaders(), av, sv) : null; 1.208 + msgId = 1.209 + av != null && message.getMessage() != null ? 1.210 + AddressingUtils.getMessageID(message.getMessage().getHeaders(), av, sv) : null; 1.211 + LOGGER.fine("In DispatchImpl." + method + " for message with action: " + action + " and msg ID: " + msgId + " msg: " + message.getMessage()); 1.212 + 1.213 + if (message.getMessage() == null) { 1.214 + LOGGER.fine("Dispatching null message for action: " + action + " and msg ID: " + msgId); 1.215 + } 1.216 + } 1.217 + } 1.218 + } 1.219 + public final Future<?> invokeAsync(T param, AsyncHandler<T> asyncHandler) { 1.220 + Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); 1.221 + try { 1.222 + if (LOGGER.isLoggable(Level.FINE)) { 1.223 + dumpParam(param, "invokeAsync(T, AsyncHandler<T>)"); 1.224 + } 1.225 + AsyncInvoker invoker = new DispatchAsyncInvoker(param); 1.226 + AsyncResponseImpl<T> ft = new AsyncResponseImpl<T>(invoker,asyncHandler); 1.227 + invoker.setReceiver(ft); 1.228 + invoker.setNonNullAsyncHandlerGiven(asyncHandler != null); 1.229 + 1.230 + ft.run(); 1.231 + return ft; 1.232 + } finally { 1.233 + ContainerResolver.getDefault().exitContainer(old); 1.234 + } 1.235 + } 1.236 + 1.237 + /** 1.238 + * Synchronously invokes a service. 1.239 + * 1.240 + * See {@link #process(Packet, RequestContext, ResponseContextReceiver)} on 1.241 + * why it takes a {@link RequestContext} and {@link ResponseContextReceiver} as a parameter. 1.242 + */ 1.243 + public final T doInvoke(T in, RequestContext rc, ResponseContextReceiver receiver){ 1.244 + Packet response = null; 1.245 + try { 1.246 + try { 1.247 + checkNullAllowed(in, rc, binding, mode); 1.248 + 1.249 + Packet message = createPacket(in); 1.250 + message.setState(Packet.State.ClientRequest); 1.251 + resolveEndpointAddress(message, rc); 1.252 + setProperties(message,true); 1.253 + response = process(message,rc,receiver); 1.254 + Message msg = response.getMessage(); 1.255 + 1.256 + // REVIEW: eliminate allowFaultResponseMsg, but make that behavior default for MessageDispatch, PacketDispatch 1.257 + if(msg != null && msg.isFault() && 1.258 + !allowFaultResponseMsg) { 1.259 + SOAPFaultBuilder faultBuilder = SOAPFaultBuilder.create(msg); 1.260 + // passing null means there is no checked excpetion we're looking for all 1.261 + // it will get back to us is a protocol exception 1.262 + throw (SOAPFaultException)faultBuilder.createException(null); 1.263 + } 1.264 + } catch (JAXBException e) { 1.265 + //TODO: i18nify 1.266 + throw new DeserializationException(DispatchMessages.INVALID_RESPONSE_DESERIALIZATION(),e); 1.267 + } catch(WebServiceException e){ 1.268 + //it could be a WebServiceException or a ProtocolException 1.269 + throw e; 1.270 + } catch(Throwable e){ 1.271 + // it could be a RuntimeException resulting due to some internal bug or 1.272 + // its some other exception resulting from user error, wrap it in 1.273 + // WebServiceException 1.274 + throw new WebServiceException(e); 1.275 + } 1.276 + 1.277 + return toReturnValue(response); 1.278 + } finally { 1.279 + // REVIEW: Move to AsyncTransportProvider 1.280 + if (response != null && response.transportBackChannel != null) 1.281 + response.transportBackChannel.close(); 1.282 + } 1.283 + } 1.284 + 1.285 + public final T invoke(T in) { 1.286 + Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); 1.287 + try { 1.288 + if (LOGGER.isLoggable(Level.FINE)) { 1.289 + dumpParam(in, "invoke(T)"); 1.290 + } 1.291 + 1.292 + return doInvoke(in,requestContext,this); 1.293 + } finally { 1.294 + ContainerResolver.getDefault().exitContainer(old); 1.295 + } 1.296 + } 1.297 + 1.298 + public final void invokeOneWay(T in) { 1.299 + Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); 1.300 + try { 1.301 + if (LOGGER.isLoggable(Level.FINE)) { 1.302 + dumpParam(in, "invokeOneWay(T)"); 1.303 + } 1.304 + 1.305 + try { 1.306 + checkNullAllowed(in, requestContext, binding, mode); 1.307 + 1.308 + Packet request = createPacket(in); 1.309 + request.setState(Packet.State.ClientRequest); 1.310 + setProperties(request,false); 1.311 + process(request,requestContext,this); 1.312 + } catch(WebServiceException e){ 1.313 + //it could be a WebServiceException or a ProtocolException 1.314 + throw e; 1.315 + } catch(Throwable e){ 1.316 + // it could be a RuntimeException resulting due to some internal bug or 1.317 + // its some other exception resulting from user error, wrap it in 1.318 + // WebServiceException 1.319 + throw new WebServiceException(e); 1.320 + } 1.321 + } finally { 1.322 + ContainerResolver.getDefault().exitContainer(old); 1.323 + } 1.324 + } 1.325 + 1.326 + void setProperties(Packet packet, boolean expectReply) { 1.327 + packet.expectReply = expectReply; 1.328 + } 1.329 + 1.330 + static boolean isXMLHttp(@NotNull WSBinding binding) { 1.331 + return binding.getBindingId().equals(BindingID.XML_HTTP); 1.332 + } 1.333 + 1.334 + static boolean isPAYLOADMode(@NotNull Service.Mode mode) { 1.335 + return mode == Service.Mode.PAYLOAD; 1.336 + } 1.337 + 1.338 + static void checkNullAllowed(@Nullable Object in, RequestContext rc, WSBinding binding, Service.Mode mode) { 1.339 + 1.340 + if (in != null) 1.341 + return; 1.342 + 1.343 + //With HTTP Binding a null invocation parameter can not be used 1.344 + //with HTTP Request Method == POST 1.345 + if (isXMLHttp(binding)){ 1.346 + if (methodNotOk(rc)) 1.347 + throw new WebServiceException(DispatchMessages.INVALID_NULLARG_XMLHTTP_REQUEST_METHOD(HTTP_REQUEST_METHOD_POST, HTTP_REQUEST_METHOD_GET)); 1.348 + } else { //soapBinding 1.349 + if (mode == Service.Mode.MESSAGE ) 1.350 + throw new WebServiceException(DispatchMessages.INVALID_NULLARG_SOAP_MSGMODE(mode.name(), Service.Mode.PAYLOAD.toString())); 1.351 + } 1.352 + } 1.353 + 1.354 + static boolean methodNotOk(@NotNull RequestContext rc) { 1.355 + String requestMethod = (String)rc.get(MessageContext.HTTP_REQUEST_METHOD); 1.356 + String request = (requestMethod == null)? HTTP_REQUEST_METHOD_POST: requestMethod; 1.357 + // if method == post or put with a null invocation parameter in xml/http binding this is not ok 1.358 + return HTTP_REQUEST_METHOD_POST.equalsIgnoreCase(request) || HTTP_REQUEST_METHOD_PUT.equalsIgnoreCase(request); 1.359 + } 1.360 + 1.361 + public static void checkValidSOAPMessageDispatch(WSBinding binding, Service.Mode mode) { 1.362 + // Dispatch<SOAPMessage> is only valid for soap binding and in Service.Mode.MESSAGE 1.363 + if (DispatchImpl.isXMLHttp(binding)) 1.364 + throw new WebServiceException(DispatchMessages.INVALID_SOAPMESSAGE_DISPATCH_BINDING(HTTPBinding.HTTP_BINDING, SOAPBinding.SOAP11HTTP_BINDING + " or " + SOAPBinding.SOAP12HTTP_BINDING)); 1.365 + if (DispatchImpl.isPAYLOADMode(mode)) 1.366 + throw new WebServiceException(DispatchMessages.INVALID_SOAPMESSAGE_DISPATCH_MSGMODE(mode.name(), Service.Mode.MESSAGE.toString())); 1.367 + } 1.368 + 1.369 + public static void checkValidDataSourceDispatch(WSBinding binding, Service.Mode mode) { 1.370 + // Dispatch<DataSource> is only valid with xml/http binding and in Service.Mode.MESSAGE 1.371 + if (!DispatchImpl.isXMLHttp(binding)) 1.372 + throw new WebServiceException(DispatchMessages.INVALID_DATASOURCE_DISPATCH_BINDING("SOAP/HTTP", HTTPBinding.HTTP_BINDING)); 1.373 + if (DispatchImpl.isPAYLOADMode(mode)) 1.374 + throw new WebServiceException(DispatchMessages.INVALID_DATASOURCE_DISPATCH_MSGMODE(mode.name(), Service.Mode.MESSAGE.toString())); 1.375 + } 1.376 + 1.377 + public final @NotNull QName getPortName() { 1.378 + return portname; 1.379 + } 1.380 + 1.381 + void resolveEndpointAddress(@NotNull final Packet message, @NotNull final RequestContext requestContext) { 1.382 + final boolean p = message.packetTakesPriorityOverRequestContext; 1.383 + 1.384 + //resolve endpoint look for query parameters, pathInfo 1.385 + String endpoint; 1.386 + if (p && message.endpointAddress != null) { 1.387 + endpoint = message.endpointAddress.toString(); 1.388 + } else { 1.389 + endpoint = (String) requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY); 1.390 + } 1.391 + // This is existing before packetTakesPriorityOverRequestContext so leaving in place. 1.392 + if (endpoint == null) { 1.393 + if (message.endpointAddress == null) throw new WebServiceException(DispatchMessages.INVALID_NULLARG_URI()); 1.394 + endpoint = message.endpointAddress.toString(); 1.395 + } 1.396 + 1.397 + String pathInfo = null; 1.398 + String queryString = null; 1.399 + if (p && message.invocationProperties.get(MessageContext.PATH_INFO) != null) { 1.400 + pathInfo = (String) message.invocationProperties.get(MessageContext.PATH_INFO); 1.401 + } else if (requestContext.get(MessageContext.PATH_INFO) != null) { 1.402 + pathInfo = (String) requestContext.get(MessageContext.PATH_INFO); 1.403 + } 1.404 + 1.405 + if (p && message.invocationProperties.get(MessageContext.QUERY_STRING) != null) { 1.406 + queryString = (String) message.invocationProperties.get(MessageContext.QUERY_STRING); 1.407 + } else if (requestContext.get(MessageContext.QUERY_STRING) != null) { 1.408 + queryString = (String) requestContext.get(MessageContext.QUERY_STRING); 1.409 + } 1.410 + 1.411 + if (pathInfo != null || queryString != null) { 1.412 + pathInfo = checkPath(pathInfo); 1.413 + queryString = checkQuery(queryString); 1.414 + if (endpoint != null) { 1.415 + try { 1.416 + final URI endpointURI = new URI(endpoint); 1.417 + endpoint = resolveURI(endpointURI, pathInfo, queryString); 1.418 + } catch (URISyntaxException e) { 1.419 + throw new WebServiceException(DispatchMessages.INVALID_URI(endpoint)); 1.420 + } 1.421 + } 1.422 + } 1.423 + // These two lines used to be inside the above if. It is outside so: 1.424 + // - in cases where there is no setting of address on a Packet before invocation or no pathInfo/queryString 1.425 + // this will just put back what it found in the requestContext - basically a noop. 1.426 + // - but when info is in the Packet this will update so it will get used later. 1.427 + // Remember - we are operating on a copied RequestContext at this point - not the sticky one in the Stub. 1.428 + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint); 1.429 + // This is not necessary because a later step will copy the resolvedEndpoint put above into message. 1.430 + //message.endpointAddress = EndpointAddress.create(endpoint); 1.431 + } 1.432 + 1.433 + protected @NotNull String resolveURI(@NotNull URI endpointURI, @Nullable String pathInfo, @Nullable String queryString) { 1.434 + String query = null; 1.435 + String fragment = null; 1.436 + if (queryString != null) { 1.437 + final URI result; 1.438 + try { 1.439 + URI tp = new URI(null, null, endpointURI.getPath(), queryString, null); 1.440 + result = endpointURI.resolve(tp); 1.441 + } catch (URISyntaxException e) { 1.442 + throw new WebServiceException(DispatchMessages.INVALID_QUERY_STRING(queryString)); 1.443 + } 1.444 + query = result.getQuery(); 1.445 + fragment = result.getFragment(); 1.446 + } 1.447 + 1.448 + final String path = (pathInfo != null) ? pathInfo : endpointURI.getPath(); 1.449 + try { 1.450 + //final URI temp = new URI(null, null, path, query, fragment); 1.451 + //return endpointURI.resolve(temp).toURL().toExternalForm(); 1.452 + // Using the following HACK instead of the above to avoid double encoding of 1.453 + // the query. Application's QUERY_STRING is encoded using URLEncoder.encode(). 1.454 + // If we use that query in URI's constructor, it is encoded again. 1.455 + // URLEncoder's encoding is not the same as URI's encoding of the query. 1.456 + // See {@link URL} 1.457 + StringBuilder spec = new StringBuilder(); 1.458 + if (path != null) { 1.459 + spec.append(path); 1.460 + } 1.461 + if (query != null) { 1.462 + spec.append("?"); 1.463 + spec.append(query); 1.464 + } 1.465 + if (fragment != null) { 1.466 + spec.append("#"); 1.467 + spec.append(fragment); 1.468 + } 1.469 + return new URL(endpointURI.toURL(), spec.toString()).toExternalForm(); 1.470 + } catch (MalformedURLException e) { 1.471 + throw new WebServiceException(DispatchMessages.INVALID_URI_RESOLUTION(path)); 1.472 + } 1.473 + } 1.474 + 1.475 + private static String checkPath(@Nullable String path) { 1.476 + //does it begin with / 1.477 + return (path == null || path.startsWith("/")) ? path : "/" + path; 1.478 + } 1.479 + 1.480 + private static String checkQuery(@Nullable String query) { 1.481 + if (query == null) return null; 1.482 + 1.483 + if (query.indexOf('?') == 0) 1.484 + throw new WebServiceException(DispatchMessages.INVALID_QUERY_LEADING_CHAR(query)); 1.485 + return query; 1.486 + } 1.487 + 1.488 + 1.489 + protected AttachmentSet setOutboundAttachments() { 1.490 + HashMap<String, DataHandler> attachments = (HashMap<String, DataHandler>) 1.491 + getRequestContext().get(MessageContext.OUTBOUND_MESSAGE_ATTACHMENTS); 1.492 + 1.493 + if (attachments != null) { 1.494 + List<Attachment> alist = new ArrayList(); 1.495 + for (Map.Entry<String, DataHandler> att : attachments.entrySet()) { 1.496 + DataHandlerAttachment dha = new DataHandlerAttachment(att.getKey(), att.getValue()); 1.497 + alist.add(dha); 1.498 + } 1.499 + return new AttachmentSetImpl(alist); 1.500 + } 1.501 + return new AttachmentSetImpl(); 1.502 + } 1.503 + 1.504 + /* private void getInboundAttachments(Message msg) { 1.505 + AttachmentSet attachments = msg.getAttachments(); 1.506 + if (!attachments.isEmpty()) { 1.507 + Map<String, DataHandler> in = new HashMap<String, DataHandler>(); 1.508 + for (Attachment attachment : attachments) 1.509 + in.put(attachment.getContentId(), attachment.asDataHandler()); 1.510 + getResponseContext().put(MessageContext.INBOUND_MESSAGE_ATTACHMENTS, in); 1.511 + } 1.512 + 1.513 + } 1.514 + */ 1.515 + 1.516 + 1.517 + /** 1.518 + * Calls {@link DispatchImpl#doInvoke(Object,RequestContext,ResponseContextReceiver)}. 1.519 + */ 1.520 + private class Invoker implements Callable { 1.521 + private final T param; 1.522 + // snapshot the context now. this is necessary to avoid concurrency issue, 1.523 + // and is required by the spec 1.524 + private final RequestContext rc = requestContext.copy(); 1.525 + 1.526 + /** 1.527 + * Because of the object instantiation order, 1.528 + * we can't take this as a constructor parameter. 1.529 + */ 1.530 + private ResponseContextReceiver receiver; 1.531 + 1.532 + Invoker(T param) { 1.533 + this.param = param; 1.534 + } 1.535 + 1.536 + public T call() throws Exception { 1.537 + if (LOGGER.isLoggable(Level.FINE)) { 1.538 + dumpParam(param, "call()"); 1.539 + } 1.540 + return doInvoke(param,rc,receiver); 1.541 + } 1.542 + 1.543 + void setReceiver(ResponseContextReceiver receiver) { 1.544 + this.receiver = receiver; 1.545 + } 1.546 + } 1.547 + 1.548 + /** 1.549 + * 1.550 + */ 1.551 + private class DispatchAsyncInvoker extends AsyncInvoker { 1.552 + private final T param; 1.553 + // snapshot the context now. this is necessary to avoid concurrency issue, 1.554 + // and is required by the spec 1.555 + private final RequestContext rc = requestContext.copy(); 1.556 + 1.557 + DispatchAsyncInvoker(T param) { 1.558 + this.param = param; 1.559 + } 1.560 + 1.561 + public void do_run () { 1.562 + checkNullAllowed(param, rc, binding, mode); 1.563 + final Packet message = createPacket(param); 1.564 + message.setState(Packet.State.ClientRequest); 1.565 + message.nonNullAsyncHandlerGiven = this.nonNullAsyncHandlerGiven; 1.566 + resolveEndpointAddress(message, rc); 1.567 + setProperties(message,true); 1.568 + 1.569 + String action = null; 1.570 + String msgId = null; 1.571 + if (LOGGER.isLoggable(Level.FINE)) { 1.572 + AddressingVersion av = DispatchImpl.this.getBinding().getAddressingVersion(); 1.573 + SOAPVersion sv = DispatchImpl.this.getBinding().getSOAPVersion(); 1.574 + action = 1.575 + av != null && message.getMessage() != null ? 1.576 + AddressingUtils.getAction(message.getMessage().getHeaders(), av, sv) : null; 1.577 + msgId = 1.578 + av != null&& message.getMessage() != null ? 1.579 + AddressingUtils.getMessageID(message.getMessage().getHeaders(), av, sv) : null; 1.580 + LOGGER.fine("In DispatchAsyncInvoker.do_run for async message with action: " + action + " and msg ID: " + msgId); 1.581 + } 1.582 + 1.583 + final String actionUse = action; 1.584 + final String msgIdUse = msgId; 1.585 + 1.586 + Fiber.CompletionCallback callback = new Fiber.CompletionCallback() { 1.587 + public void onCompletion(@NotNull Packet response) { 1.588 + 1.589 + if (LOGGER.isLoggable(Level.FINE)) { 1.590 + LOGGER.fine("Done with processAsync in DispatchAsyncInvoker.do_run, and setting response for async message with action: " + actionUse + " and msg ID: " + msgIdUse); 1.591 + } 1.592 + 1.593 + Message msg = response.getMessage(); 1.594 + 1.595 + if (LOGGER.isLoggable(Level.FINE)) { 1.596 + LOGGER.fine("Done with processAsync in DispatchAsyncInvoker.do_run, and setting response for async message with action: " + actionUse + " and msg ID: " + msgIdUse + " msg: " + msg); 1.597 + } 1.598 + 1.599 + try { 1.600 + if(msg != null && msg.isFault() && 1.601 + !allowFaultResponseMsg) { 1.602 + SOAPFaultBuilder faultBuilder = SOAPFaultBuilder.create(msg); 1.603 + // passing null means there is no checked excpetion we're looking for all 1.604 + // it will get back to us is a protocol exception 1.605 + throw (SOAPFaultException)faultBuilder.createException(null); 1.606 + } 1.607 + responseImpl.setResponseContext(new ResponseContext(response)); 1.608 + responseImpl.set(toReturnValue(response), null); 1.609 + } catch (JAXBException e) { 1.610 + //TODO: i18nify 1.611 + responseImpl.set(null, new DeserializationException(DispatchMessages.INVALID_RESPONSE_DESERIALIZATION(),e)); 1.612 + } catch(WebServiceException e){ 1.613 + //it could be a WebServiceException or a ProtocolException 1.614 + responseImpl.set(null, e); 1.615 + } catch(Throwable e){ 1.616 + // It could be any RuntimeException resulting due to some internal bug. 1.617 + // or its some other exception resulting from user error, wrap it in 1.618 + // WebServiceException 1.619 + responseImpl.set(null, new WebServiceException(e)); 1.620 + } 1.621 + } 1.622 + public void onCompletion(@NotNull Throwable error) { 1.623 + if (LOGGER.isLoggable(Level.FINE)) { 1.624 + 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()); 1.625 + } 1.626 + if (error instanceof WebServiceException) { 1.627 + responseImpl.set(null, error); 1.628 + 1.629 + } else { 1.630 + //its RuntimeException or some other exception resulting from user error, wrap it in 1.631 + // WebServiceException 1.632 + responseImpl.set(null, new WebServiceException(error)); 1.633 + } 1.634 + } 1.635 + }; 1.636 + processAsync(responseImpl,message,rc, callback); 1.637 + } 1.638 + } 1.639 + 1.640 + public void setOutboundHeaders(Object... headers) { 1.641 + throw new UnsupportedOperationException(); 1.642 + } 1.643 + 1.644 + static final String HTTP_REQUEST_METHOD_GET="GET"; 1.645 + static final String HTTP_REQUEST_METHOD_POST="POST"; 1.646 + static final String HTTP_REQUEST_METHOD_PUT="PUT"; 1.647 + 1.648 + @Deprecated 1.649 + public static Dispatch<Source> createSourceDispatch(QName port, Mode mode, WSServiceDelegate owner, Tube pipe, BindingImpl binding, WSEndpointReference epr) { 1.650 + if(isXMLHttp(binding)) 1.651 + return new RESTSourceDispatch(port,mode,owner,pipe,binding,epr); 1.652 + else 1.653 + return new SOAPSourceDispatch(port,mode,owner,pipe,binding,epr); 1.654 + } 1.655 + 1.656 + public static Dispatch<Source> createSourceDispatch(WSPortInfo portInfo, Mode mode, BindingImpl binding, WSEndpointReference epr) { 1.657 + if (isXMLHttp(binding)) 1.658 + return new RESTSourceDispatch(portInfo, mode, binding, epr); 1.659 + else 1.660 + return new SOAPSourceDispatch(portInfo, mode, binding, epr); 1.661 + } 1.662 +}