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

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
     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 +}

mercurial