blob: cd566266814587cdad5b7fab6f6cb0c8f9a518b6 [file] [log] [blame]
/*
* Copyright 2006 The Apache Software Foundation.
* Copyright 2006 International Business Machines Corp.
*
* Licensed 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;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.soap.SOAPBinding;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.jaxws.AxisController;
import org.apache.axis2.jaxws.BindingProvider;
import org.apache.axis2.jaxws.ExceptionFactory;
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.AxisInvocationController;
import org.apache.axis2.jaxws.core.controller.InvocationController;
import org.apache.axis2.jaxws.handler.PortData;
import org.apache.axis2.jaxws.impl.AsyncListener;
import org.apache.axis2.jaxws.message.Message;
import org.apache.axis2.jaxws.spi.ServiceDelegate;
import org.apache.axis2.jaxws.util.Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class BaseDispatch<T> extends BindingProvider
implements javax.xml.ws.Dispatch {
private Log log = LogFactory.getLog(BaseDispatch.class);
//FIXME: Remove the AxisController completely and replace with InvocationController
protected AxisController axisController = null;
protected InvocationController ic;
protected ServiceDelegate serviceDelegate;
protected ServiceClient serviceClient;
protected Mode mode;
protected PortData port;
protected BaseDispatch(PortData p) {
super();
port = p;
ic = new AxisInvocationController();
setRequestContext();
}
protected BaseDispatch(AxisController ac) {
super();
//FIXME: Remove this when we remove the AxisController
axisController = ac;
ic = new AxisInvocationController();
setRequestContext();
}
/**
* 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 AsyncListener createAsyncListener();
public Object invoke(Object obj) throws WebServiceException {
if (log.isDebugEnabled()) {
log.debug("Entered synchronous invocation: BaseDispatch.invoke()");
}
//Check for valid invocation parameter
obj = validateInvocationParam(obj);
// 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();
invocationContext.setRequestMessageContext(requestMsgCtx);
Message requestMsg = createMessageFromValue(obj);
setupMessageProperties(requestMsg);
requestMsgCtx.setMessage(requestMsg);
// Copy the properties from the request context into the MessageContext
requestMsgCtx.getProperties().putAll(requestContext);
// Send the request using the InvocationController
ic.invoke(invocationContext);
MessageContext responseMsgCtx = invocationContext.getResponseMessageContext();
//FIXME: This is temporary until more of the Message model is available
Message responseMsg = responseMsgCtx.getMessage();
Object returnObj = getValueFromMessage(responseMsg);
if (log.isDebugEnabled()) {
log.debug("Synchronous invocation completed: BaseDispatch.invoke()");
}
return returnObj;
}
public void invokeOneWay(Object obj) throws WebServiceException{
if (log.isDebugEnabled()) {
log.debug("Entered one-way invocation: BaseDispatch.invokeOneWay()");
}
//Check for valid invocation parameter
obj = validateInvocationParam(obj);
// 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();
invocationContext.setRequestMessageContext(requestMsgCtx);
Message requestMsg = createMessageFromValue(obj);
setupMessageProperties(requestMsg);
requestMsgCtx.setMessage(requestMsg);
// Copy the properties from the request context into the MessageContext
requestMsgCtx.getProperties().putAll(requestContext);
// Send the request using the InvocationController
ic.invokeOneWay(invocationContext);
if (log.isDebugEnabled()) {
log.debug("One-way invocation completed: BaseDispatch.invokeOneWay()");
}
return;
}
public Future<?> invokeAsync(Object obj, AsyncHandler asynchandler) throws WebServiceException {
if (log.isDebugEnabled()) {
log.debug("Entered asynchronous (callback) invocation: BaseDispatch.invokeAsync()");
}
//Check for valid invocation parameter
obj = validateInvocationParam(obj);
// 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();
invocationContext.setRequestMessageContext(requestMsgCtx);
Message requestMsg = createMessageFromValue(obj);
setupMessageProperties(requestMsg);
requestMsgCtx.setMessage(requestMsg);
// Copy the properties from the request context into the MessageContext
requestMsgCtx.getProperties().putAll(requestContext);
// 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.
AsyncListener listener = createAsyncListener();
invocationContext.setAsyncListener(listener);
// Send the request using the InvocationController
Future<?> asyncResponse = ic.invokeAsync(invocationContext, asynchandler);
if (log.isDebugEnabled()) {
log.debug("Asynchronous (callback) invocation sent: BaseDispatch.invokeAsync()");
}
return asyncResponse;
}
public Response invokeAsync(Object obj)throws WebServiceException{
throw new UnsupportedOperationException("Async (polling) invocations are not yet supported.");
}
//FIXME: This needs to be moved up to the BindingProvider and should actually
//be called "initRequestContext()" or something like that.
protected void setRequestContext(){
String endPointAddress = port.getEndpointAddress();
//WSDLWrapper wsdl = axisController.getWSDLContext();
//QName serviceName = axisController.getServiceName();
//QName portName = axisController.getPortName();
if(endPointAddress != null && !"".equals(endPointAddress)){
getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endPointAddress);
}
//else if(wsdl != null){
// String soapAddress = wsdl.getSOAPAddress(serviceName, portName);
// getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, soapAddress);
//}
//if(wsdl != null){
// String soapAction = wsdl.getSOAPAction(serviceName, portName);
// getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapAction);
//}
}
public ServiceDelegate getServiceDelegate() {
return serviceDelegate;
}
public void setServiceDelegate(ServiceDelegate sd) {
serviceDelegate = sd;
}
public void setServiceClient(ServiceClient sc) {
serviceClient = sc;
}
public Mode getMode() {
return mode;
}
public void setMode(Mode m) {
mode = m;
}
public PortData getPort() {
return port;
}
/*
* 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.
if (binding != null && binding instanceof SOAPBinding) {
SOAPBinding soapBinding = (SOAPBinding) binding;
if (soapBinding.isMTOMEnabled())
msg.setMTOMEnabled(true);
}
}
/**
* Validate invocation parameter value.
* @param object
* @return object
*/
private Object validateInvocationParam(Object object){
Object obj = object;
String bindingId = port.getBindingID();
try {
if(bindingId.equalsIgnoreCase(SOAPBinding.SOAP11HTTP_BINDING) ||
bindingId.equalsIgnoreCase(SOAPBinding.SOAP11HTTP_MTOM_BINDING)){
if(mode.toString().equalsIgnoreCase(Mode.PAYLOAD.toString()) && object == null){
//TODO Per JAXWS 2.0 Specification in Section 4.3.2, may need to send a soap
// message with empty body. For now, implementation will through a
// NullPointerException wrapped in WebServiceException
throw new NullPointerException("Error: Dispatch invocation value is NULL");
}
}
else if(object == null){
throw new NullPointerException("Error: Dispatch invocation value is NULL");
}
}
catch(NullPointerException npe){
throw ExceptionFactory.makeWebServiceException(npe);
}
catch(Exception e){
throw ExceptionFactory.makeWebServiceException(e);
}
return obj;
}
}