You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by xu...@apache.org on 2011/05/30 17:20:22 UTC
svn commit: r1129214 - in /geronimo/bundles/trunk/axis2: pom.xml
src/main/java/org/apache/axis2/jaxws/client/dispatch/
src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
Author: xuhaihong
Date: Mon May 30 15:20:22 2011
New Revision: 1129214
URL: http://svn.apache.org/viewvc?rev=1129214&view=rev
Log:
Try the temp fix for connection leak while using Dispatch.invokeOneWay
Added:
geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/
geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java (with props)
Modified:
geronimo/bundles/trunk/axis2/pom.xml
Modified: geronimo/bundles/trunk/axis2/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/bundles/trunk/axis2/pom.xml?rev=1129214&r1=1129213&r2=1129214&view=diff
==============================================================================
--- geronimo/bundles/trunk/axis2/pom.xml (original)
+++ geronimo/bundles/trunk/axis2/pom.xml Mon May 30 15:20:22 2011
@@ -311,7 +311,8 @@
org/apache/axis2/jaxws/description/impl/EndpointDescriptionImpl$6.class=target/classes/org/apache/axis2/jaxws/description/impl/EndpointDescriptionImpl$6.class,
org/apache/axis2/transport/http/AbstractHTTPSender.class=target/classes/org/apache/axis2/transport/http/AbstractHTTPSender.class,
org/apache/axis2/client/OperationClient.class=target/classes/org/apache/axis2/client/OperationClient.class,
- org/apache/axis2/jaxws/description/impl/PostRI216MethodRetrieverImpl.class=target/classes/org/apache/axis2/jaxws/description/impl/PostRI216MethodRetrieverImpl.class
+ org/apache/axis2/jaxws/description/impl/PostRI216MethodRetrieverImpl.class=target/classes/org/apache/axis2/jaxws/description/impl/PostRI216MethodRetrieverImpl.class,
+ org/apache/axis2/jaxws/client/dispatch/BaseDispatch.class=target/classes/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.class
</Include-Resource>
<SPI-Provider>true</SPI-Provider>
</instructions>
Added: geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
URL: http://svn.apache.org/viewvc/geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java?rev=1129214&view=auto
==============================================================================
--- geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java (added)
+++ geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java Mon May 30 15:20:22 2011
@@ -0,0 +1,998 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axis2.jaxws.client.dispatch;
+
+import org.apache.axis2.addressing.EndpointReference;
+import org.apache.axis2.client.ServiceClient;
+import org.apache.axis2.description.AxisOperation;
+import org.apache.axis2.description.AxisService;
+import org.apache.axis2.description.Parameter;
+import org.apache.axis2.engine.AxisConfiguration;
+import org.apache.axis2.jaxws.BindingProvider;
+import org.apache.axis2.jaxws.ExceptionFactory;
+import org.apache.axis2.jaxws.client.async.AsyncResponse;
+import org.apache.axis2.jaxws.core.InvocationContext;
+import org.apache.axis2.jaxws.core.InvocationContextFactory;
+import org.apache.axis2.jaxws.core.MessageContext;
+import org.apache.axis2.jaxws.core.controller.InvocationController;
+import org.apache.axis2.jaxws.core.controller.InvocationControllerFactory;
+import org.apache.axis2.jaxws.description.EndpointDescription;
+import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
+import org.apache.axis2.jaxws.description.OperationDescription;
+import org.apache.axis2.jaxws.i18n.Messages;
+import org.apache.axis2.jaxws.marshaller.impl.alt.MethodMarshallerUtils;
+import org.apache.axis2.jaxws.message.Message;
+import org.apache.axis2.jaxws.registry.FactoryRegistry;
+import org.apache.axis2.jaxws.spi.Binding;
+import org.apache.axis2.jaxws.spi.Constants;
+import org.apache.axis2.jaxws.spi.ServiceDelegate;
+import org.apache.axis2.jaxws.spi.migrator.ApplicationContextMigratorUtil;
+import org.apache.axis2.transport.http.HTTPConstants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.w3c.dom.Node;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPBody;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.ProtocolException;
+import javax.xml.ws.Response;
+import javax.xml.ws.Service.Mode;
+import javax.xml.ws.WebServiceException;
+import javax.xml.ws.WebServiceFeature;
+import javax.xml.ws.http.HTTPBinding;
+import javax.xml.ws.soap.SOAPBinding;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
+public abstract class BaseDispatch<T> extends BindingProvider
+ implements javax.xml.ws.Dispatch {
+
+ private static Log log = LogFactory.getLog(BaseDispatch.class);
+
+ protected InvocationController ic;
+
+ protected ServiceClient serviceClient;
+
+ protected Mode mode;
+
+ protected BaseDispatch(ServiceDelegate svcDelgate,
+ EndpointDescription epDesc,
+ EndpointReference epr,
+ String addressingNamespace,
+ WebServiceFeature... features) {
+ super(svcDelgate, epDesc, epr, addressingNamespace, features);
+
+ InvocationControllerFactory icf = (InvocationControllerFactory) FactoryRegistry.getFactory(InvocationControllerFactory.class);
+ ic = icf.getInvocationController();
+
+ if (ic == null) {
+ throw new WebServiceException(Messages.getMessage("missingInvocationController"));
+ }
+ }
+
+ /**
+ * Take the input object and turn it into an OMElement so that it can be sent.
+ *
+ * @param value
+ * @return
+ */
+ protected abstract Message createMessageFromValue(Object value);
+
+ /**
+ * Given a message, return the business object based on the requestor's required format (PAYLOAD
+ * vs. MESSAGE) and datatype.
+ *
+ * @param message
+ * @return
+ */
+ protected abstract Object getValueFromMessage(Message message);
+
+ /**
+ * Creates an instance of the AsyncListener that is to be used for waiting for async responses.
+ *
+ * @return a configured AsyncListener instance
+ */
+ protected abstract AsyncResponse createAsyncResponseListener();
+
+
+ /**
+ * Note to developer: When making a change or fix to this method, please consider
+ * all 5 Proxy/Dispatch "invoke" methods now available in JAX-WS. For Dispatch,
+ * these are:
+ * 1) Synchronous invoke()
+ * 2) invokeOneWay()
+ * 3) invokeAsynch (Future)
+ * 4) invokeAsynch (Callback)
+ *
+ * For Proxy:
+ * 5) invokeSEIMethod()
+ *
+ */
+ public Object invoke(Object obj) throws WebServiceException {
+
+ // Catch all exceptions and rethrow an appropriate WebService Exception
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Entered synchronous invocation: BaseDispatch.invoke()");
+ }
+
+ // Create the InvocationContext instance for this request/response flow.
+ InvocationContext invocationContext =
+ InvocationContextFactory.createInvocationContext(null);
+ invocationContext.setServiceClient(serviceClient);
+
+ // Create the MessageContext to hold the actual request message and its
+ // associated properties
+ MessageContext requestMsgCtx = new MessageContext();
+ requestMsgCtx.getAxisMessageContext().setProperty(BINDING_PROVIDER, this);
+ requestMsgCtx.setEndpointDescription(getEndpointDescription());
+ invocationContext.setRequestMessageContext(requestMsgCtx);
+
+ /*
+ * TODO: review: make sure the handlers are set on the InvocationContext
+ * This implementation of the JAXWS runtime does not use Endpoint, which
+ * would normally be the place to initialize and store the handler list.
+ * In lieu of that, we will have to intialize and store them on the
+ * InvocationContext. also see the InvocationContextFactory. On the client
+ * side, the binding is not yet set when we call into that factory, so the
+ * handler list doesn't get set on the InvocationContext object there. Thus
+ * we gotta do it here.
+ */
+
+ // be sure to use whatever handlerresolver is registered on the Service
+ Binding binding = (Binding) getBinding();
+ invocationContext.setHandlers(binding.getHandlerChain());
+
+ initMessageContext(obj, requestMsgCtx);
+
+ // call common init method for all invoke* paths
+ preInvokeInit(invocationContext);
+
+ // Migrate the properties from the client request context bag to
+ // the request MessageContext.
+ ApplicationContextMigratorUtil.performMigrationToMessageContext(
+ Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID,
+ getRequestContext(), requestMsgCtx);
+
+ // Perform the WebServiceFeature configuration requested by the user.
+ binding.configure(requestMsgCtx, this);
+
+ // Initializing the message context above will put the outbound message onto the messageContext
+ // Determine the operation if possible from the outbound message. If it can not be determined
+ // it will be set to null. In this case, an anonymous operation will be used. Note that determining
+ // the operation will mean deserializing the message. That means that any WebServiceFeatures must have
+ // been configured first so that any relevant configurations (such as MTOM) have been initialized prior to
+ // the message being deserialized. This is particularly true for Dispatch<JAXB Element>.
+ requestMsgCtx.setOperationDescription(getOperationDescriptionForDispatch(requestMsgCtx));
+
+ // Send the request using the InvocationController
+ ic.invoke(invocationContext);
+
+ MessageContext responseMsgCtx = invocationContext.getResponseMessageContext();
+ responseMsgCtx.setEndpointDescription(requestMsgCtx.getEndpointDescription());
+
+ // Migrate the properties from the response MessageContext back
+ // to the client response context bag.
+ ApplicationContextMigratorUtil.performMigrationFromMessageContext(
+ Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID,
+ getResponseContext(), responseMsgCtx);
+
+ if (hasFaultResponse(responseMsgCtx)) {
+ WebServiceException wse = BaseDispatch.getFaultResponse(responseMsgCtx);
+ throw wse;
+ }
+
+ // Get the return object
+ Object returnObj = null;
+ try {
+ Message responseMsg = responseMsgCtx.getMessage();
+ returnObj = getValueFromMessage(responseMsg);
+ }
+ finally {
+ // Free the incoming input stream
+ try {
+ responseMsgCtx.freeInputStream();
+ }
+ catch (Throwable t) {
+ throw ExceptionFactory.makeWebServiceException(t);
+ }
+ }
+
+ //Check to see if we need to maintain session state
+ checkMaintainSessionState(requestMsgCtx, invocationContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Synchronous invocation completed: BaseDispatch.invoke()");
+ }
+
+ return returnObj;
+ } catch (WebServiceException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invoke(): Synchronous invocation failed, "
+ + "caught a WebServiceException: ", e);
+ }
+ throw e;
+ } catch (Exception e) {
+ // All exceptions are caught and rethrown as a WebServiceException
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invoke(): Synchronous invocation failed, caught an Exception, " +
+ "wrapping into a WebServiceException. Exception caught: ", e);
+ }
+ throw ExceptionFactory.makeWebServiceException(e);
+ }
+ }
+
+ /**
+ * Given a JAXWS Message Context which contains an outbound service-requester Message for a Dispatch client,
+ * determine the OperationDescription for the operation contained in that Dispatch message.
+ *
+ * Note that operation resolution can be disabled by a property setting.
+ * @see org.apache.axis2.jaxws.Constants.DISPATCH_CLIENT_OUTBOUND_RESOLUTION
+ *
+ * @param requestMessageCtx JAXWS Message Context containing the outbound Dispatch message
+ * @return the OperationDescription corresponding to the operation contained in the Dispatch message, or null
+ * if it can not be determined or if dispatch operation resolution is disabled via a property.
+ */
+ private OperationDescription getOperationDescriptionForDispatch(MessageContext requestMessageCtx) {
+ OperationDescription operationDesc = null;
+ if (dispatchOperationResolutionEnabled()) {
+ EndpointInterfaceDescription endpointInterfaceDesc = getEndpointDescription().getEndpointInterfaceDescription();
+ // The SEI interface could be null (for example if there was no SEI and all the ports were dynamically added).
+ // If there is an SEI, then try to determine the operation for the outbound dispatch message.
+ if (endpointInterfaceDesc != null) {
+ QName bodyElementQName = getBodyElementQNameFromDispatchMessage(requestMessageCtx);
+ operationDesc = determineOperationDescFromBodyElementQName(endpointInterfaceDesc, bodyElementQName);
+ }
+ }
+ return operationDesc;
+ }
+
+ /**
+ * Returns the OperationDescription corresponding to the bodyElementQName passed in. What that body element corresponds to
+ * depends on the type of the message:
+ * - For Doc/Lit/Wrapped, the body element is the operation name
+ * - For Doc/Lit/Bare, the body element is the element name contained in the wsdl:message wsdl:part
+ * - For RPC, the body element is effectively the operation name.
+ *
+ * @param endpointInterfaceDesc The interface (i.e. SEI) on which to search for the operation
+ * @param bodyElementQName the QName of the first body element for which to find the operation
+ *
+ * @return The OperationDescription corresponding to the body element QName or null if one can not be found.
+ */
+ private OperationDescription determineOperationDescFromBodyElementQName(EndpointInterfaceDescription endpointInterfaceDesc,
+ QName bodyElementQName) {
+ OperationDescription operationDesc = null;
+
+ // If there's no bodyElementQName for us to work with, there's nothing more we can do.
+ if (bodyElementQName != null) {
+ // This logic mimics the code in SOAPMessageBodyBasedOperationDispatcher.findOperation. We will look for
+ // the AxisOperation corresponding to the body element name. Note that we are searching for the AxisOperation instead
+ // of searching through the OperationDescriptions so that we can use the getOperationByMessageElementQName
+ // for the Doc/Lit/Bare case. Once we have the AxisOperation, we'll use that to find the Operation Description.
+ AxisService axisService = endpointInterfaceDesc.getEndpointDescription().getAxisService();
+ AxisOperation axisOperation = null;
+
+ // Doc/Lit/Wrapped and RPC, the operation name is the first body element qname
+ axisOperation = axisService.getOperation(new QName(bodyElementQName.getLocalPart()));
+
+ if (axisOperation == null) {
+ // Doc/Lit/Bare, the first body element qname is the element name contained in the wsdl:message part
+ axisOperation = axisService.getOperationByMessageElementQName(bodyElementQName);
+ }
+
+ if (axisOperation == null) {
+ // Not sure why we wouldn't have found the operation above using just the localPart rather than the full QName used here,
+ // but this is what SOAPMessageBodyBasedOperationDispatcher.findOperation does.
+ axisOperation = axisService.getOperation(bodyElementQName);
+ }
+
+ // If we found an axis operation, then find the operation description that corresponds to it
+ if (axisOperation != null) {
+ OperationDescription allOpDescs[] = endpointInterfaceDesc.getDispatchableOperations();
+ for (OperationDescription checkOpDesc : allOpDescs ) {
+ AxisOperation checkAxisOperation = checkOpDesc.getAxisOperation();
+ if (checkAxisOperation == axisOperation) {
+ operationDesc = checkOpDesc;
+ break;
+ }
+ }
+ }
+ }
+ return operationDesc;
+ }
+
+ /**
+ * Answer if operation resolution on outbound messages for dispatch clients should be done. The default value
+ * is TRUE, enabling operation resolution. Resolution can be disabled via a property on the AxisConfiguration
+ * or on the RequestContext.
+ *
+ * Operation resolution is also disabled if a non-null value is specified on the request context for the Action
+ *
+ * @see org.apache.axis2.jaxws.Constants.DISPATCH_CLIENT_OUTBOUND_RESOLUTION
+ * @see javax.xml.ws.BindingProvider.SOAPACTION_USE_PROPERTY
+ * @see javax.xml.ws.BindingProvider.SOAPACTION_URI_PROPERTY
+ *
+ * @return true if operation resolution should be performed on outbound
+ */
+ private boolean dispatchOperationResolutionEnabled() {
+ boolean resolutionEnabled = true;
+
+ // See if any properties disabled operation resolution
+ // Check for System property setting
+ String flagValue = getProperty(org.apache.axis2.jaxws.Constants.DISPATCH_CLIENT_OUTBOUND_RESOLUTION);
+
+ // If no System property was set, see if one was set on this request context.
+ if (flagValue == null) {
+ flagValue = (String) getRequestContext().get(org.apache.axis2.jaxws.Constants.DISPATCH_CLIENT_OUTBOUND_RESOLUTION);
+ }
+
+ // If any property was set, check the value.
+ if (flagValue != null) {
+ if ("false".equalsIgnoreCase(flagValue)) {
+ resolutionEnabled = false;
+ } else if ("true".equalsIgnoreCase(flagValue)) {
+ resolutionEnabled = true;
+ }
+ }
+
+ // If a property didn't disable resolution, then see if a URI value was specified.
+ // If so, we'll use that later and there's no need to do operation resolution.
+ if (resolutionEnabled) {
+ Boolean useSoapAction = (Boolean) getRequestContext().get(SOAPACTION_USE_PROPERTY);
+ if (useSoapAction != null && useSoapAction.booleanValue()) {
+ String soapAction = (String) getRequestContext().get(SOAPACTION_URI_PROPERTY);
+ if (soapAction != null) {
+ resolutionEnabled = false;
+ }
+ }
+ }
+ return resolutionEnabled;
+ }
+
+ /**
+ * Retrieve the specified property from the AxisConfiguration.
+ *
+ * @param key The property to retrieve from the AxisConfiguration
+ * @return the value associated with the property or null if the property did not exist on the configuration.
+ */
+ private String getProperty(String key) {
+ String propertyValue = null;
+ AxisConfiguration axisConfig = serviceDelegate.getServiceDescription().getAxisConfigContext().getAxisConfiguration();
+ Parameter parameter = axisConfig.getParameter(key);
+ if (parameter != null) {
+ propertyValue = (String) parameter.getValue();
+ }
+ return propertyValue;
+ }
+
+
+ /**
+ * Given a JAXWS Message Context which contains an outbound service-requester Message for a Dispatch client,
+ * determine the QName of the first body element contained in that message.
+ *
+ * @param requestMessageCtx requestMessageCtx JAXWS Message Context containing the outbound Dispatch message
+ * @return the QName of the first body element contained in the outbound Dispatch message, or null if it
+ * can not be determined.
+ */
+ QName getBodyElementQNameFromDispatchMessage(MessageContext requestMessageCtx) {
+ QName bodyElementQName = null;
+ Message dispatchMessage = requestMessageCtx.getMessage();
+ SOAPMessage soapMessage = dispatchMessage.getAsSOAPMessage();
+ try {
+ SOAPBody soapBody = soapMessage.getSOAPBody();
+ Node firstElement = soapBody.getFirstChild();
+ // A Doc/Lit/Bare message may not have a firsElement. The soap:Body element may be empty if there
+ // are no arguments to the operation.
+ if (firstElement != null) {
+ String ns = firstElement.getNamespaceURI();
+ String lp= firstElement.getLocalName();
+ // A Doc/Lit/Bare message may not have a localPart on the element. That can happen if the first element
+ // is the argument value and there is no wrapper element surrounding it.
+ if (lp != null) {
+ bodyElementQName = new QName(ns, lp);
+ }
+ }
+ } catch (SOAPException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Unabled to get the first body element from the outbound dispatch message", e);
+ }
+ }
+ return bodyElementQName;
+ }
+
+ protected void initMessageContext(Object obj, MessageContext requestMsgCtx) {
+ Message requestMsg = createRequestMessage(obj);
+ setupMessageProperties(requestMsg);
+ requestMsgCtx.setMessage(requestMsg);
+ // handle HTTP_REQUEST_METHOD property
+ String method = (String)requestContext.get(javax.xml.ws.handler.MessageContext.HTTP_REQUEST_METHOD);
+ if (method != null) {
+ requestMsgCtx.setProperty(org.apache.axis2.Constants.Configuration.HTTP_METHOD, method);
+ }
+ }
+
+ /**
+ * Note to developer: When making a change or fix to this method, please consider
+ * all 5 Proxy/Dispatch "invoke" methods now available in JAX-WS. For Dispatch,
+ * these are:
+ * 1) Synchronous invoke()
+ * 2) invokeOneWay()
+ * 3) invokeAsynch (Future)
+ * 4) invokeAsynch (Callback)
+ *
+ * For Proxy:
+ * 5) invokeSEIMethod()
+ *
+ */
+ public void invokeOneWay(Object obj) throws WebServiceException {
+
+ // All exceptions are caught and rethrown as a WebServiceException
+ MessageContext requestMsgCtx = null;
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Entered one-way invocation: BaseDispatch.invokeOneWay()");
+ }
+
+ // Create the InvocationContext instance for this request/response flow.
+ InvocationContext invocationContext =
+ InvocationContextFactory.createInvocationContext(null);
+ invocationContext.setServiceClient(serviceClient);
+
+ // Create the MessageContext to hold the actual request message and its
+ // associated properties
+ requestMsgCtx = new MessageContext();
+ requestMsgCtx.getAxisMessageContext().setProperty(BINDING_PROVIDER, this);
+ requestMsgCtx.setEndpointDescription(getEndpointDescription());
+ invocationContext.setRequestMessageContext(requestMsgCtx);
+
+ /*
+ * TODO: review: make sure the handlers are set on the InvocationContext
+ * This implementation of the JAXWS runtime does not use Endpoint, which
+ * would normally be the place to initialize and store the handler list.
+ * In lieu of that, we will have to intialize and store them on the
+ * InvocationContext. also see the InvocationContextFactory. On the client
+ * side, the binding is not yet set when we call into that factory, so the
+ * handler list doesn't get set on the InvocationContext object there. Thus
+ * we gotta do it here.
+ */
+
+ // be sure to use whatever handlerresolver is registered on the Service
+ Binding binding = (Binding) getBinding();
+ invocationContext.setHandlers(binding.getHandlerChain());
+
+ initMessageContext(obj, requestMsgCtx);
+
+ /*
+ * if SESSION_MAINTAIN_PROPERTY is true, and the client app has explicitly set a HEADER_COOKIE on the request context, assume the client
+ * app is expecting the HEADER_COOKIE to be the session id. If we were establishing a new session, no cookie would be sent, and the
+ * server would reply with a "Set-Cookie" header, which is copied as a "Cookie"-keyed property to the service context during response.
+ * In this case, if we succeed in using an existing server session, no "Set-Cookie" header will be returned, and therefore no
+ * "Cookie"-keyed property would be set on the service context. So, let's copy our request context HEADER_COOKIE key to the service
+ * context now to prevent the "no cookie" exception in BindingProvider.setupSessionContext. It is possible the server does not support
+ * sessions, in which case no error occurs, but the client app would assume it is participating in a session.
+ */
+ if ((requestContext.containsKey(BindingProvider.SESSION_MAINTAIN_PROPERTY)) && ((Boolean)requestContext.get(BindingProvider.SESSION_MAINTAIN_PROPERTY))) {
+ if ((requestContext.containsKey(HTTPConstants.HEADER_COOKIE)) && (requestContext.get(HTTPConstants.HEADER_COOKIE) != null)) {
+ if (invocationContext.getServiceClient().getServiceContext().getProperty(HTTPConstants.HEADER_COOKIE) == null) {
+ invocationContext.getServiceClient().getServiceContext().setProperty(HTTPConstants.HEADER_COOKIE, requestContext.get(HTTPConstants.HEADER_COOKIE));
+ if (log.isDebugEnabled()) {
+ log.debug("Client-app defined Cookie property (assume to be session cookie) on request context copied to service context." +
+ " Caution: server may or may not support sessions, but client app will not be informed when not supported.");
+ }
+ }
+ }
+ }
+
+ // call common init method for all invoke* paths
+ preInvokeInit(invocationContext);
+
+ // Migrate the properties from the client request context bag to
+ // the request MessageContext.
+ ApplicationContextMigratorUtil.performMigrationToMessageContext(
+ Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID,
+ getRequestContext(), requestMsgCtx);
+
+ // Perform the WebServiceFeature configuration requested by the user.
+ binding.configure(requestMsgCtx, this);
+
+ // Initializing the message context above will put the outbound message onto the messageContext
+ // Determine the operation if possible from the outbound message. If it can not be determined
+ // it will be set to null. In this case, an anonymous operation will be used. Note that determining
+ // the operation will mean deserializing the message. That means that any WebServiceFeatures must have
+ // been configured first so that any relevant configurations (such as MTOM) have been initialized prior to
+ // the message being deserialized. This is particularly true for Dispatch<JAXB Element>.
+ requestMsgCtx.setOperationDescription(getOperationDescriptionForDispatch(requestMsgCtx));
+
+ // Send the request using the InvocationController
+ ic.invokeOneWay(invocationContext);
+
+ //Check to see if we need to maintain session state
+ checkMaintainSessionState(requestMsgCtx, invocationContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("One-way invocation completed: BaseDispatch.invokeOneWay()");
+ }
+
+ return;
+ } catch (WebServiceException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeOneWay(): One-way invocation failed, " +
+ "caught a WebServiceException: ", e);
+ }
+ throw e;
+ } catch (Exception e) {
+ // All exceptions are caught and rethrown as a WebServiceException
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeOneWay(): One-way invocation failed, " +
+ "caught an Exception, wrapping into a WebServicesException. " +
+ " Exception caught: ", e);
+ }
+ throw ExceptionFactory.makeWebServiceException(e);
+ } finally {
+ try {
+ if (requestMsgCtx != null && requestMsgCtx.getAxisMessageContext() != null) {
+ org.apache.axis2.context.MessageContext axisMsgCtx = requestMsgCtx.getAxisMessageContext();
+ if (axisMsgCtx.getTransportOut() != null && axisMsgCtx.getTransportOut().getSender() != null) {
+ axisMsgCtx.getTransportOut().getSender().cleanup(axisMsgCtx);
+ }
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ /**
+ * Note to developer: When making a change or fix to this method, please consider
+ * all 5 Proxy/Dispatch "invoke" methods now available in JAX-WS. For Dispatch,
+ * these are:
+ * 1) Synchronous invoke()
+ * 2) invokeOneWay()
+ * 3) invokeAsynch (Future)
+ * 4) invokeAsynch (Callback)
+ *
+ * For Proxy:
+ * 5) invokeSEIMethod()
+ *
+ */
+ public Future<?> invokeAsync(Object obj, AsyncHandler asynchandler) throws WebServiceException {
+
+ // All exceptions are caught and rethrown as a WebServiceException
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Entered asynchronous (callback) invocation: BaseDispatch.invokeAsync()");
+ }
+
+ // Create the InvocationContext instance for this request/response flow.
+ InvocationContext invocationContext =
+ InvocationContextFactory.createInvocationContext(null);
+ invocationContext.setServiceClient(serviceClient);
+
+ // Create the MessageContext to hold the actual request message and its
+ // associated properties
+ MessageContext requestMsgCtx = new MessageContext();
+ requestMsgCtx.getAxisMessageContext().setProperty(BINDING_PROVIDER, this);
+ requestMsgCtx.setEndpointDescription(getEndpointDescription());
+ invocationContext.setRequestMessageContext(requestMsgCtx);
+
+ /*
+ * TODO: review: make sure the handlers are set on the InvocationContext
+ * This implementation of the JAXWS runtime does not use Endpoint, which
+ * would normally be the place to initialize and store the handler list.
+ * In lieu of that, we will have to intialize and store them on the
+ * InvocationContext. also see the InvocationContextFactory. On the client
+ * side, the binding is not yet set when we call into that factory, so the
+ * handler list doesn't get set on the InvocationContext object there. Thus
+ * we gotta do it here.
+ */
+
+ // be sure to use whatever handlerresolver is registered on the Service
+ Binding binding = (Binding) getBinding();
+ invocationContext.setHandlers(binding.getHandlerChain());
+
+ initMessageContext(obj, requestMsgCtx);
+ /*
+ * if SESSION_MAINTAIN_PROPERTY is true, and the client app has explicitly set a HEADER_COOKIE on the request context, assume the client
+ * app is expecting the HEADER_COOKIE to be the session id. If we were establishing a new session, no cookie would be sent, and the
+ * server would reply with a "Set-Cookie" header, which is copied as a "Cookie"-keyed property to the service context during response.
+ * In this case, if we succeed in using an existing server session, no "Set-Cookie" header will be returned, and therefore no
+ * "Cookie"-keyed property would be set on the service context. So, let's copy our request context HEADER_COOKIE key to the service
+ * context now to prevent the "no cookie" exception in BindingProvider.setupSessionContext. It is possible the server does not support
+ * sessions, in which case no error occurs, but the client app would assume it is participating in a session.
+ */
+ if ((requestContext.containsKey(BindingProvider.SESSION_MAINTAIN_PROPERTY)) && ((Boolean)requestContext.get(BindingProvider.SESSION_MAINTAIN_PROPERTY))) {
+ if ((requestContext.containsKey(HTTPConstants.HEADER_COOKIE)) && (requestContext.get(HTTPConstants.HEADER_COOKIE) != null)) {
+ if (invocationContext.getServiceClient().getServiceContext().getProperty(HTTPConstants.HEADER_COOKIE) == null) {
+ invocationContext.getServiceClient().getServiceContext().setProperty(HTTPConstants.HEADER_COOKIE, requestContext.get(HTTPConstants.HEADER_COOKIE));
+ if (log.isDebugEnabled()) {
+ log.debug("Client-app defined Cookie property (assume to be session cookie) on request context copied to service context." +
+ " Caution: server may or may not support sessions, but client app will not be informed when not supported.");
+ }
+ }
+ }
+ }
+
+ // call common init method for all invoke* paths
+ preInvokeInit(invocationContext);
+
+ // Migrate the properties from the client request context bag to
+ // the request MessageContext.
+ ApplicationContextMigratorUtil.performMigrationToMessageContext(
+ Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID,
+ getRequestContext(), requestMsgCtx);
+
+ // Perform the WebServiceFeature configuration requested by the user.
+ binding.configure(requestMsgCtx, this);
+
+ // Initializing the message context above will put the outbound message onto the messageContext
+ // Determine the operation if possible from the outbound message. If it can not be determined
+ // it will be set to null. In this case, an anonymous operation will be used. Note that determining
+ // the operation will mean deserializing the message. That means that any WebServiceFeatures must have
+ // been configured first so that any relevant configurations (such as MTOM) have been initialized prior to
+ // the message being deserialized. This is particularly true for Dispatch<JAXB Element>.
+ requestMsgCtx.setOperationDescription(getOperationDescriptionForDispatch(requestMsgCtx));
+
+ // Setup the Executor that will be used to drive async responses back to
+ // the client.
+ // FIXME: We shouldn't be getting this from the ServiceDelegate, rather each
+ // Dispatch object should have it's own.
+ Executor e = serviceDelegate.getExecutor();
+ invocationContext.setExecutor(e);
+
+ // Create the AsyncListener that is to be used by the InvocationController.
+ AsyncResponse listener = createAsyncResponseListener();
+ invocationContext.setAsyncResponseListener(listener);
+
+ // Send the request using the InvocationController
+ Future<?> asyncResponse = ic.invokeAsync(invocationContext, asynchandler);
+
+ //Check to see if we need to maintain session state
+ checkMaintainSessionState(requestMsgCtx, invocationContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Asynchronous (callback) invocation sent: BaseDispatch.invokeAsync()");
+ }
+
+ return asyncResponse;
+ } catch (WebServiceException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeAsync() [Callback]: Asynchronous invocation failed, " +
+ "caught a WebServiceException: ", e);
+ }
+ throw e;
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeAsync() [Callback]: Asynchronous invocation failed, " +
+ "caught an Exception, wrapping into a WebServiceException. Exception caught: ", e);
+ }
+ // All exceptions are caught and rethrown as a WebServiceException
+ throw ExceptionFactory.makeWebServiceException(e);
+ }
+ }
+
+ /**
+ * Note to developer: When making a change or fix to this method, please consider
+ * all 5 Proxy/Dispatch "invoke" methods now available in JAX-WS. For Dispatch,
+ * these are:
+ * 1) Synchronous invoke()
+ * 2) invokeOneWay()
+ * 3) invokeAsynch (Future)
+ * 4) invokeAsynch (Callback)
+ *
+ * For Proxy:
+ * 5) invokeSEIMethod()
+ *
+ */
+ public Response invokeAsync(Object obj) throws WebServiceException {
+
+ // All exceptions are caught and rethrown as a WebServiceException
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Entered asynchronous (polling) invocation: BaseDispatch.invokeAsync()");
+ }
+
+ // Create the InvocationContext instance for this request/response flow.
+ InvocationContext invocationContext =
+ InvocationContextFactory.createInvocationContext(null);
+ invocationContext.setServiceClient(serviceClient);
+
+ // Create the MessageContext to hold the actual request message and its
+ // associated properties
+ MessageContext requestMsgCtx = new MessageContext();
+ requestMsgCtx.getAxisMessageContext().setProperty(BINDING_PROVIDER, this);
+ requestMsgCtx.setEndpointDescription(getEndpointDescription());
+ invocationContext.setRequestMessageContext(requestMsgCtx);
+
+ /*
+ * TODO: review: make sure the handlers are set on the InvocationContext
+ * This implementation of the JAXWS runtime does not use Endpoint, which
+ * would normally be the place to initialize and store the handler list.
+ * In lieu of that, we will have to intialize and store them on the
+ * InvocationContext. also see the InvocationContextFactory. On the client
+ * side, the binding is not yet set when we call into that factory, so the
+ * handler list doesn't get set on the InvocationContext object there. Thus
+ * we gotta do it here.
+ */
+
+ // be sure to use whatever handlerresolver is registered on the Service
+ Binding binding = (Binding) getBinding();
+ invocationContext.setHandlers(binding.getHandlerChain());
+
+ initMessageContext(obj, requestMsgCtx);
+
+ /*
+ * if SESSION_MAINTAIN_PROPERTY is true, and the client app has explicitly set a HEADER_COOKIE on the request context, assume the client
+ * app is expecting the HEADER_COOKIE to be the session id. If we were establishing a new session, no cookie would be sent, and the
+ * server would reply with a "Set-Cookie" header, which is copied as a "Cookie"-keyed property to the service context during response.
+ * In this case, if we succeed in using an existing server session, no "Set-Cookie" header will be returned, and therefore no
+ * "Cookie"-keyed property would be set on the service context. So, let's copy our request context HEADER_COOKIE key to the service
+ * context now to prevent the "no cookie" exception in BindingProvider.setupSessionContext. It is possible the server does not support
+ * sessions, in which case no error occurs, but the client app would assume it is participating in a session.
+ */
+ if ((requestContext.containsKey(BindingProvider.SESSION_MAINTAIN_PROPERTY)) && ((Boolean)requestContext.get(BindingProvider.SESSION_MAINTAIN_PROPERTY))) {
+ if ((requestContext.containsKey(HTTPConstants.HEADER_COOKIE)) && (requestContext.get(HTTPConstants.HEADER_COOKIE) != null)) {
+ if (invocationContext.getServiceClient().getServiceContext().getProperty(HTTPConstants.HEADER_COOKIE) == null) {
+ invocationContext.getServiceClient().getServiceContext().setProperty(HTTPConstants.HEADER_COOKIE, requestContext.get(HTTPConstants.HEADER_COOKIE));
+ if (log.isDebugEnabled()) {
+ log.debug("Client-app defined Cookie property (assume to be session cookie) on request context copied to service context." +
+ " Caution: server may or may not support sessions, but client app will not be informed when not supported.");
+ }
+ }
+ }
+ }
+
+ // call common init method for all invoke* paths
+ preInvokeInit(invocationContext);
+
+ // Migrate the properties from the client request context bag to
+ // the request MessageContext.
+ ApplicationContextMigratorUtil.performMigrationToMessageContext(
+ Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID,
+ getRequestContext(), requestMsgCtx);
+
+ // Perform the WebServiceFeature configuration requested by the user.
+ binding.configure(requestMsgCtx, this);
+
+ // Initializing the message context above will put the outbound message onto the messageContext
+ // Determine the operation if possible from the outbound message. If it can not be determined
+ // it will be set to null. In this case, an anonymous operation will be used. Note that determining
+ // the operation will mean deserializing the message. That means that any WebServiceFeatures must have
+ // been configured first so that any relevant configurations (such as MTOM) have been initialized prior to
+ // the message being deserialized. This is particularly true for Dispatch<JAXB Element>.
+ requestMsgCtx.setOperationDescription(getOperationDescriptionForDispatch(requestMsgCtx));
+
+
+ // Setup the Executor that will be used to drive async responses back to
+ // the client.
+ // FIXME: We shouldn't be getting this from the ServiceDelegate, rather each
+ // Dispatch object should have it's own.
+ Executor e = serviceDelegate.getExecutor();
+ invocationContext.setExecutor(e);
+
+ // Create the AsyncListener that is to be used by the InvocationController.
+ AsyncResponse listener = createAsyncResponseListener();
+ invocationContext.setAsyncResponseListener(listener);
+
+ // Send the request using the InvocationController
+ Response asyncResponse = ic.invokeAsync(invocationContext);
+
+ //Check to see if we need to maintain session state
+ checkMaintainSessionState(requestMsgCtx, invocationContext);
+
+ if (log.isDebugEnabled()) {
+ log.debug("Asynchronous (polling) invocation sent: BaseDispatch.invokeAsync()");
+ }
+
+ return asyncResponse;
+ } catch (WebServiceException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeAsync() [Polling]: Asynchronous invocation failed, " +
+ "caught a WebServiceException: ", e);
+ }
+ throw e;
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("BaseDispatch.invokeAsync() [Polling]: Asynchronous invocation failed, " +
+ "caught an Exception, wrapping into a WebServiceException. Exception caught: ",e);
+ }
+ // All exceptions are caught and rethrown as a WebServiceException
+ throw ExceptionFactory.makeWebServiceException(e);
+ }
+ }
+
+ public void setServiceClient(ServiceClient sc) {
+ serviceClient = sc;
+ }
+
+ public Mode getMode() {
+ return mode;
+ }
+
+ public void setMode(Mode m) {
+ mode = m;
+ }
+
+ /**
+ * Returns the fault that is contained within the MessageContext for an invocation. If no fault
+ * exists, null will be returned.
+ *
+ * @param msgCtx
+ * @return
+ */
+ public static WebServiceException getFaultResponse(MessageContext msgCtx) {
+ try {
+ Message msg = msgCtx.getMessage();
+ if (msg != null && msg.isFault()) {
+ //XMLFault fault = msg.getXMLFault();
+ // 4.3.2 conformance bullet 1 requires a ProtocolException here
+ ProtocolException pe =
+ MethodMarshallerUtils.createSystemException(msg.getXMLFault(), msg);
+ if (msgCtx.getLocalException() != null) {
+ // If a local exception occured, set it as the initial cause of the
+ // exception that will be returned
+ ExceptionFactory.setInitialCause(pe, msgCtx.getLocalException());
+ }
+ return pe;
+ } else if (msgCtx.getLocalException() != null) {
+ // use the factory, it'll throw the right thing:
+ return ExceptionFactory.makeWebServiceException(msgCtx.getLocalException());
+ }
+ } finally {
+ // Free the incoming input stream
+ try {
+ msgCtx.freeInputStream();
+ } catch (IOException ioe) {
+ return ExceptionFactory.makeWebServiceException(ioe);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a boolean indicating whether or not the MessageContext contained a fault.
+ *
+ * @param msgCtx
+ * @return
+ */
+ public boolean hasFaultResponse(MessageContext msgCtx) {
+ if(!msgCtx.getAxisMessageContext().getOptions().isExceptionToBeThrownOnSOAPFault()){
+ if(log.isDebugEnabled()){
+ log.debug("msgCtx.Options.isExceptionToBeThrownOnSOAPFault set to false; Exception will not be thrown on fault");
+ }
+ return false;
+ }
+ if (msgCtx.getMessage() != null && msgCtx.getMessage().isFault())
+ return true;
+ else if (msgCtx.getLocalException() != null)
+ return true;
+ else
+ return false;
+ }
+
+ /*
+ * Configure any properties that will be needed on the Message
+ */
+ private void setupMessageProperties(Message msg) {
+ // If the user has enabled MTOM on the SOAPBinding, we need
+ // to make sure that gets pushed to the Message object.
+ Binding binding = (Binding) getBinding();
+ if (binding != null && binding instanceof SOAPBinding) {
+ SOAPBinding soapBinding = (SOAPBinding)binding;
+ if (soapBinding.isMTOMEnabled())
+ msg.setMTOMEnabled(true);
+ }
+ }
+
+ /*
+ * Checks to see if the parameter for the invocation is valid
+ * given the scenario that the client is operating in. There are
+ * some cases when nulls are allowed and others where it is
+ * an error.
+ */
+ private boolean isValidInvocationParam(Object object) {
+ String bindingId = endpointDesc.getClientBindingID();
+
+ // If no bindingId was found, use the default.
+ if (bindingId == null) {
+ bindingId = SOAPBinding.SOAP11HTTP_BINDING;
+ }
+
+ // If it's not an HTTP_BINDING, then we can allow for null params,
+ // but only in PAYLOAD mode per JAX-WS Section 4.3.2.
+ if (!bindingId.equals(HTTPBinding.HTTP_BINDING)) {
+ if (mode.equals(Mode.MESSAGE) && object == null) {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("dispatchNullParamMessageMode"));
+ }
+ } else {
+ // In all cases (PAYLOAD and MESSAGE) we must throw a WebServiceException
+ // if the parameter is null and request method is POST or PUT.
+ if (object == null && isPOSTorPUTRequest()) {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("dispatchNullParamHttpBinding"));
+ }
+ }
+
+ if (object instanceof DOMSource) {
+ DOMSource ds = (DOMSource)object;
+ if (ds.getNode() == null && ds.getSystemId() == null) {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("dispatchBadDOMSource"));
+ }
+ }
+
+ // If we've gotten this far, then all is good.
+ return true;
+ }
+
+ private boolean isPOSTorPUTRequest() {
+ String method = (String)this.requestContext.get(javax.xml.ws.handler.MessageContext.HTTP_REQUEST_METHOD);
+ // if HTTP_REQUEST_METHOD is not specified, assume it is a POST method
+ return (method == null ||
+ HTTPConstants.HEADER_POST.equalsIgnoreCase(method) ||
+ HTTPConstants.HEADER_PUT.equalsIgnoreCase(method));
+ }
+
+ private Message createRequestMessage(Object obj) throws WebServiceException {
+
+ // Check to see if the object is a valid invocation parameter.
+ // Then create the message from the object.
+ // If an exception occurs, it is local to the client and therefore is a
+ // WebServiceException (and not ProtocolExceptions).
+ // This code complies with JAX-WS 2.0 sections 4.3.2, 4.3.3 and 4.3.4.
+ if (!isValidInvocationParam(obj)) {
+ throw ExceptionFactory.makeWebServiceException(Messages.getMessage("dispatchInvalidParam"));
+ }
+ Message requestMsg = null;
+ try {
+ requestMsg = createMessageFromValue(obj);
+ } catch (Throwable t) {
+ // The webservice exception wraps the thrown exception.
+ throw ExceptionFactory.makeWebServiceException(t);
+ }
+ return requestMsg;
+ }
+
+ private void preInvokeInit(InvocationContext requestIC) {
+ /*
+ * if SESSION_MAINTAIN_PROPERTY is true, and the client app has explicitly set a HEADER_COOKIE on the request context, assume the client
+ * app is expecting the HEADER_COOKIE to be the session id. If we were establishing a new session, no cookie would be sent, and the
+ * server would reply with a "Set-Cookie" header, which is copied as a "Cookie"-keyed property to the service context during response.
+ * In this case, if we succeed in using an existing server session, no "Set-Cookie" header will be returned, and therefore no
+ * "Cookie"-keyed property would be set on the service context. So, let's copy our request context HEADER_COOKIE key to the service
+ * context now to prevent the "no cookie" exception in BindingProvider.setupSessionContext. It is possible the server does not support
+ * sessions, in which case no error occurs, but the client app would assume it is participating in a session.
+ */
+ if ((requestContext.containsKey(BindingProvider.SESSION_MAINTAIN_PROPERTY)) && ((Boolean)requestContext.get(BindingProvider.SESSION_MAINTAIN_PROPERTY))) {
+ if ((requestContext.containsKey(HTTPConstants.HEADER_COOKIE)) && (requestContext.get(HTTPConstants.HEADER_COOKIE) != null)) {
+ if (requestIC.getServiceClient().getServiceContext().getProperty(HTTPConstants.HEADER_COOKIE) == null) {
+ requestIC.getServiceClient().getServiceContext().setProperty(HTTPConstants.HEADER_COOKIE, requestContext.get(HTTPConstants.HEADER_COOKIE));
+ if (log.isDebugEnabled()) {
+ log.debug("Client-app defined Cookie property (assume to be session cookie) on request context copied to service context." +
+ " Caution: server may or may not support sessions, but client app will not be informed when not supported.");
+ }
+ }
+ }
+ }
+ }
+}
Propchange: geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/bundles/trunk/axis2/src/main/java/org/apache/axis2/jaxws/client/dispatch/BaseDispatch.java
------------------------------------------------------------------------------
svn:mime-type = text/plain