blob: c3d10390f5609abc738c33ac51c1b68cf6cf9f9b [file] [log] [blame]
/*
* 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.core.controller.impl;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.core.InvocationContext;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.core.controller.InvocationController;
import org.apache.axis2.jaxws.core.controller.InvocationPattern;
import org.apache.axis2.jaxws.core.util.MessageContextUtils;
import org.apache.axis2.jaxws.handler.AttachmentsAdapter;
import org.apache.axis2.jaxws.handler.HandlerChainProcessor;
import org.apache.axis2.jaxws.handler.HandlerInvokerUtils;
import org.apache.axis2.jaxws.handler.SOAPHeadersAdapter;
import org.apache.axis2.jaxws.handler.TransportHeadersAdapter;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.util.Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* An abstract implementation of the InvocationController interface.
*/
public abstract class InvocationControllerImpl implements InvocationController {
private static final Log log = LogFactory.getLog(InvocationControllerImpl.class);
/*
* (non-Javadoc)
* @see org.apache.axis2.jaxws.core.controller.InvocationController#invoke(org.apache.axis2.jaxws.core.InvocationContext)
*/
public InvocationContext invoke(InvocationContext ic) {
if (log.isDebugEnabled()) {
log.debug("Invocation pattern: synchronous");
}
// Check to make sure we at least have a valid InvocationContext
// and request MessageContext
if (ic == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr1"));
}
if (ic.getRequestMessageContext() == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr2"));
}
MessageContext request = ic.getRequestMessageContext();
MessageContext response = null;
request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.SYNC);
// Invoke outbound handlers.
boolean success =
HandlerInvokerUtils.invokeOutboundHandlers(request.getMEPContext(),
ic.getHandlers(),
HandlerChainProcessor.MEP.REQUEST,
false);
if (success) {
prepareRequest(request);
response = doInvoke(request);
prepareResponse(response);
// make sure request and response contexts share a single parent
response.setMEPContext(request.getMEPContext());
/*
* TODO TODO TODO review
*
* In most cases we are adding the endpointDesc to the
* MessageContext. Notice here that the "response" object is set by
* the call to doInvoke. It's a new context we are now working with.
* The invokeInboundHandlers uses that context way down in
* createMessageContext --> ContextUtils.addProperties()
*
* This may also occur in the AsyncResponse class when calling
* invokeInboundHandlers
*
* For now, make sure the endpointDesc is set on the response
* context.
*/
response.setEndpointDescription(request.getEndpointDescription());
// Invoke inbound handlers.
TransportHeadersAdapter.install(response);
AttachmentsAdapter.install(response);
SOAPHeadersAdapter.install(response);
HandlerInvokerUtils.invokeInboundHandlers(response.getMEPContext(),
ic.getHandlers(),
HandlerChainProcessor.MEP.RESPONSE,
false);
} else { // the outbound handler chain must have had a problem, and
// we've reversed directions
response = MessageContextUtils.createMinimalResponseMessageContext(request);
// since we've reversed directions, the message has "become a
// make sure request and response contexts share a single parent
response.setMEPContext(request.getMEPContext());
response.setMessage(request.getMessage());
}
ic.setResponseMessageContext(response);
return ic;
}
protected abstract MessageContext doInvoke(MessageContext request);
/*
* (non-Javadoc)
* @see org.apache.axis2.jaxws.core.controller.InvocationController#invokeOneWay(org.apache.axis2.jaxws.core.InvocationContext)
*/
public void invokeOneWay(InvocationContext ic) throws Exception {
if (log.isDebugEnabled()) {
log.debug("Invocation pattern: one-way");
}
// Check to make sure we at least have a valid InvocationContext
// and request MessageContext
if (ic == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr1"));
}
if (ic.getRequestMessageContext() == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr2"));
}
MessageContext request = ic.getRequestMessageContext();
request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ONEWAY);
// Invoke outbound handlers.
boolean success =
HandlerInvokerUtils.invokeOutboundHandlers(request.getMEPContext(),
ic.getHandlers(),
HandlerChainProcessor.MEP.REQUEST,
true);
if (success) {
prepareRequest(request);
doInvokeOneWay(request);
} else { // the outbound handler chain must have had a problem, and we've reversed directions
// check to see if problem is due to a handler throwing an exception. If so, throw it,
// even in this oneWay invoke.
Exception e = request.getCausedByException();
if (e != null) {
throw (Exception)e.getCause();
}
}
return;
}
protected abstract void doInvokeOneWay(MessageContext mc);
/*
* (non-Javadoc)
* @see org.apache.axis2.jaxws.core.controller.InvocationController#invokeAsync(org.apache.axis2.jaxws.core.InvocationContext)
*/
public Response invokeAsync(InvocationContext ic) {
if (log.isDebugEnabled()) {
log.debug("Invocation pattern: asynchronous(polling)");
}
// Check to make sure we at least have a valid InvocationContext
// and request MessageContext
if (ic == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr1"));
}
if (ic.getRequestMessageContext() == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr2"));
}
MessageContext request = ic.getRequestMessageContext();
request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_POLLING);
Response resp = null;
// Invoke outbound handlers.
// TODO uncomment, and get the EndpointDescription from the request context, which should soon be available
boolean success =
HandlerInvokerUtils.invokeOutboundHandlers(request.getMEPContext(),
ic.getHandlers(),
HandlerChainProcessor.MEP.REQUEST,
false);
if (success) {
prepareRequest(request);
resp = doInvokeAsync(request);
} else
{ // the outbound handler chain must have had a problem, and we've reversed directions
// since we've reversed directions, the message has "become a response message" (section 9.3.2.1, footnote superscript 2)
// TODO we know the message is a fault message, we should
// convert it to an exception and throw it.
// something like:
//throw new AxisFault(request.getMessage());
}
return resp;
}
public abstract Response doInvokeAsync(MessageContext mc);
/*
* (non-Javadoc)
* @see org.apache.axis2.jaxws.core.controller.InvocationController#invokeAsync(org.apache.axis2.jaxws.core.InvocationContext, javax.xml.ws.AsyncHandler)
*/
public Future<?> invokeAsync(InvocationContext ic, AsyncHandler asyncHandler) {
if (log.isDebugEnabled()) {
log.debug("Invocation pattern: asynchronous(callback)");
}
// Check to make sure we at least have a valid InvocationContext
// and request MessageContext
if (ic == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr1"));
}
if (ic.getRequestMessageContext() == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("ICErr2"));
}
if ((ic.getExecutor() != null) && (ic.getExecutor() instanceof ExecutorService)) {
ExecutorService es = (ExecutorService) ic.getExecutor();
if (es.isShutdown()) {
// the executor service is shutdown and won't accept new tasks
// so return an error back to the client
throw ExceptionFactory.makeWebServiceException(Messages
.getMessage("ExecutorShutdown"));
}
}
MessageContext request = ic.getRequestMessageContext();
request.setProperty(Constants.INVOCATION_PATTERN, InvocationPattern.ASYNC_CALLBACK);
Future<?> future = null;
// Invoke outbound handlers.
boolean success =
HandlerInvokerUtils.invokeOutboundHandlers(request.getMEPContext(),
ic.getHandlers(),
HandlerChainProcessor.MEP.REQUEST,
false);
if (success) {
prepareRequest(request);
future = doInvokeAsync(request, asyncHandler);
} else { // the outbound handler chain must have had a problem, and
// we've reversed directions
// since we've reversed directions, the message has "become a
// response message" (section 9.3.2.1, footnote superscript 2)
// TODO: how do we deal with this? The response message may or may
// not be a fault
// message. We do know that the direction has reversed, so somehow
// we need to
// flow immediately out of the async and give the exception and/or
// response object
// back to the client app without calling
// AsyncResponse.processResponse or processFault
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("invokeAsyncErr"));
// throw new AxisFault(request.getMessage());
}
return future;
}
public abstract Future<?> doInvokeAsync(MessageContext mc, AsyncHandler asyncHandler);
/**
* Abstract method that must be implemented by whoever is providing the specific client binding.
* Once this is called, everything that is needed to invoke the operation must be available in
* the MessageContext.
*
* @param mc
*/
protected abstract void prepareRequest(MessageContext mc);
/**
* Abstract method that must be implemented by whoever is providing the specific client binding.
* This is called after the response has come back and allows the client binding to put
* whatever info it has in the response MessageContext.
*
* @param mc
*/
protected abstract void prepareResponse(MessageContext mc);
}