/* * 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 MessageContext 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(); } }