blob: 199fd8f766fc8d60fd7409e86bd28ae3c88b6328 [file] [log] [blame]
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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.axis.client ;
import javax.xml.namespace.QName;
import javax.xml.rpc.handler.HandlerChain;
import org.apache.axis.AxisEngine;
import org.apache.axis.AxisFault;
import org.apache.axis.Constants;
import org.apache.axis.EngineConfiguration;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.configuration.EngineConfigurationFactoryFinder;
import org.apache.axis.handlers.HandlerInfoChainFactory;
import org.apache.axis.handlers.soap.MustUnderstandChecker;
import org.apache.axis.handlers.soap.SOAPService;
import org.apache.axis.utils.Messages;
import org.apache.commons.logging.Log;
/**
* Provides the equivalent of an "Axis engine" on the client side.
* Subclasses hardcode initialization & setup logic for particular
* client-side transports.
*
* @author Rob Jellinghaus (robj@unrealities.com)
* @author Doug Davis (dug@us.ibm.com)
* @author Glen Daniels (gdaniels@allaire.com)
*/
public class AxisClient extends AxisEngine {
protected static Log log =
LogFactory.getLog(AxisClient.class.getName());
MustUnderstandChecker checker = new MustUnderstandChecker(null);
public AxisClient(EngineConfiguration config) {
super(config);
}
public AxisClient() {
this(EngineConfigurationFactoryFinder.newFactory().
getClientEngineConfig());
}
/**
* @return this instance, as this is the client engine
*/
public AxisEngine getClientEngine () {
return this;
}
/**
* Main routine of the AXIS engine. In short we locate the appropriate
* handler for the desired service and invoke() it.
*
* @param msgContext the <code>MessageContext</code> to invoke relative
* to
* @throws AxisFault if anything goes wrong during invocation
*/
public void invoke(MessageContext msgContext) throws AxisFault {
if (log.isDebugEnabled()) {
log.debug("Enter: AxisClient::invoke");
}
String hName = null;
Handler h = null;
HandlerChain handlerImpl = null;
// save previous context
MessageContext previousContext = getCurrentMessageContext();
try {
// set active context
setCurrentMessageContext(msgContext);
hName = msgContext.getStrProp(MessageContext.ENGINE_HANDLER);
if (log.isDebugEnabled()) {
log.debug("EngineHandler: " + hName);
}
if (hName != null) {
h = getHandler(hName);
if (h != null)
h.invoke(msgContext);
else
throw new AxisFault("Client.error",
Messages.getMessage("noHandler00",
hName),
null, null);
} else {
/* Now we do the 'real' work. The flow is basically: */
/* */
/* Service Specific Request Chain */
/* Global Request Chain */
/* Transport Request Chain - must have a send at the end */
/* Transport Response Chain */
/* Global Response Chain */
/* Service Specific Response Chain */
/* Protocol Specific-Handler/Checker */
/**************************************************************/
SOAPService service = null;
msgContext.setPastPivot(false);
/* Process the Service Specific Request Chain */
/**********************************************/
service = msgContext.getService();
if (service != null) {
h = service.getRequestHandler();
if (h != null)
h.invoke(msgContext);
}
/* Process the Global Request Chain */
/**********************************/
if ((h = getGlobalRequest()) != null)
h.invoke(msgContext);
/* Process the JAX-RPC Handlers - handleRequest.
* Make sure to set the pastPivot to true if this returns a
* false. In that case we do not invoke the transport request
* chain. Also note that if a a false was returned from the
* JAX-RPC handler chain, then the chain still holds the index
* of the handler that returned false. So when we invoke the
* handleResponse method of the chain, it will correctly call
* the handleResponse from that specific handler instance. So
* do not destroy the chain at this point - the chain will be
* destroyed in the finally block.
*/
handlerImpl = getJAXRPChandlerChain(msgContext);
if (handlerImpl != null) {
try {
if (!handlerImpl.handleRequest(msgContext)) {
msgContext.setPastPivot(true);
}
} catch (RuntimeException re) {
handlerImpl.destroy(); // WS4EE 1.1 6.2.2.1 Handler Life Cycle. "RuntimeException" --> destroy handler
throw re;
}
}
/** Process the Transport Specific stuff
*
* NOTE: Somewhere in here there is a handler which actually
* sends the message and receives a response. Generally
* this is the pivot point in the Transport chain. But invoke
* this only if pivot point has not been set to false. This
* can be set to false if any of the JAX-RPC handler's
* handleRequest returned false.
*/
if (!msgContext.getPastPivot()) {
hName = msgContext.getTransportName();
if (hName != null && (h = getTransport(hName)) != null) {
try {
h.invoke(msgContext);
} catch (AxisFault e) {
throw e;
}
} else {
throw new AxisFault(Messages.getMessage("noTransport00",
hName));
}
}
msgContext.setPastPivot(true);
if (!msgContext.isPropertyTrue(Call.ONE_WAY)) {
if ((handlerImpl != null) &&
!msgContext.isPropertyTrue(Call.ONE_WAY)) {
try {
handlerImpl.handleResponse(msgContext);
} catch (RuntimeException ex) {
handlerImpl.destroy(); // WS4EE 1.1 6.2.2.1 Handler Life Cycle. "RuntimeException" --> destroy handler
throw ex;
}
}
/* Process the Global Response Chain */
/***********************************/
if ((h = getGlobalResponse()) != null) {
h.invoke(msgContext);
}
/* Process the Service-Specific Response Chain */
/***********************************************/
if (service != null) {
h = service.getResponseHandler();
if (h != null) {
h.invoke(msgContext);
}
}
// Do SOAP Semantics checks here - this needs to be a call
// to a pluggable object/handler/something
if (msgContext.isPropertyTrue(Call.CHECK_MUST_UNDERSTAND,
true)) {
checker.invoke(msgContext);
}
}
}
} catch (Exception e) {
// Should we even bother catching it ?
if (e instanceof AxisFault) {
throw (AxisFault) e;
} else {
log.debug(Messages.getMessage("exception00"), e);
throw AxisFault.makeFault(e);
}
} finally {
if (handlerImpl != null) {
handlerImpl.destroy();
}
// restore previous state
setCurrentMessageContext(previousContext);
}
if (log.isDebugEnabled()) {
log.debug("Exit: AxisClient::invoke");
}
}
/**
* @param context Stores the Service, port QName and optionnaly a HandlerInfoChainFactory
* @return Returns a HandlerChain if one has been specified
*/
protected HandlerChain getJAXRPChandlerChain(MessageContext context) {
java.util.List chain = null;
HandlerInfoChainFactory hiChainFactory = null;
boolean clientSpecified = false;
Service service = (Service) context.getProperty(Call.WSDL_SERVICE);
if(service == null) {
return null;
}
QName portName = (QName) context.getProperty(Call.WSDL_PORT_NAME);
if(portName == null) {
return null;
}
javax.xml.rpc.handler.HandlerRegistry registry;
registry = service.getHandlerRegistry();
if(registry != null) {
chain = registry.getHandlerChain(portName);
if ((chain != null) && (!chain.isEmpty())) {
hiChainFactory = new HandlerInfoChainFactory(chain);
clientSpecified = true;
}
}
// Otherwise, use the container support
if (!clientSpecified) {
SOAPService soapService = context.getService();
if (soapService != null) {
// A client configuration exists for this service. Check
// to see if there is a HandlerInfoChain configured on it.
hiChainFactory = (HandlerInfoChainFactory)
soapService.getOption(Constants.ATTR_HANDLERINFOCHAIN);
}
}
if (hiChainFactory == null) {
return null;
}
return hiChainFactory.createHandlerChain();
}
}