Axis源码分析-服务端处理请求并响应(三)

在Axis源码分析-Web服务部署(二)中
http://dead-knight.iteye.com/blog/732961
已经将两种web部署方式进行了分析
其中涉及了服务端AxisServlet初始化。以及对get、post请求的监听。
服务端处理请求实际上就是AxisServlet中doPost所做的事情。
AxisServlet中doPost源码:
public void doPost(HttpServletRequest req, HttpServletResponse res) throws
            ServletException, IOException {
        long t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
        String soapAction = null;
        MessageContext msgContext = null;
        if (isDebug) {
            log.debug("Enter: doPost()");
        }
        if (tlog.isDebugEnabled()) {
            t0 = System.currentTimeMillis();
        }

        Message responseMsg = null;
        String contentType = null;

        try {
            //获取服务端引擎。初始化工作在init方法已完成
            AxisEngine engine = getEngine();

            if (engine == null) {
                // !!! should return a SOAP fault...
                ServletException se =
                        new ServletException(Messages.getMessage("noEngine00"));
                log.debug("No Engine!", se);
                throw se;
            }

            res.setBufferSize(1024 * 8); // provide performance boost.

            /** get message context w/ various properties set
             */
            //MessageContext初始化以及属性设置
            msgContext = createMessageContext(engine, req, res);

            // ? OK to move this to 'getMessageContext',
            // ? where it would also be picked up for 'doGet()' ?
            if (securityProvider != null) {
                if (isDebug) {
                    log.debug("securityProvider:" + securityProvider);
                }
                msgContext.setProperty(MessageContext.SECURITY_PROVIDER,
                                       securityProvider);
            }

            /* Get request message
             */
            //构造请求消息体。req.getInputStream()即为请求输入流
              //http request header+xml(soap格式)
            Message requestMsg =
                    new Message(req.getInputStream(),
                                false,
                                req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
                                req.getHeader(HTTPConstants.
                                              HEADER_CONTENT_LOCATION));
            // Transfer HTTP headers to MIME headers for request message.
            MimeHeaders requestMimeHeaders = requestMsg.getMimeHeaders();
            for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) {
                String headerName = (String) e.nextElement();
                for (Enumeration f = req.getHeaders(headerName);
                                     f.hasMoreElements(); ) {
                    String headerValue = (String) f.nextElement();
                    requestMimeHeaders.addHeader(headerName, headerValue);
                }
            }

            if (isDebug) {
                log.debug("Request Message:" + requestMsg);

                /* Set the request(incoming) message field in the context */
                /**********************************************************/
            }
            msgContext.setRequestMessage(requestMsg);
            String url = HttpUtils.getRequestURL(req).toString();
            msgContext.setProperty(MessageContext.TRANS_URL, url);
            // put character encoding of request to message context
            // in order to reuse it during the whole process.
            String requestEncoding;
            try {
                requestEncoding = (String) requestMsg.getProperty(SOAPMessage.
                        CHARACTER_SET_ENCODING);
                if (requestEncoding != null) {
                    msgContext.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
                                           requestEncoding);
                }
            } catch (SOAPException e1) {
            }

            try {
                soapAction = getSoapAction(req);

                if (soapAction != null) {
                    msgContext.setUseSOAPAction(true);
                    msgContext.setSOAPActionURI(soapAction);
                }

                msgContext.setSession(new AxisHttpSession(req));

                if (tlog.isDebugEnabled()) {
                    t1 = System.currentTimeMillis();
                }
                if (isDebug) {
                    log.debug("Invoking Axis Engine.");
                    //here we run the message by the engine
                }
                //AxisServer执行invoke
                engine.invoke(msgContext);
                if (isDebug) {
                    log.debug("Return from Axis Engine.");
                }
                if (tlog.isDebugEnabled()) {
                    t2 = System.currentTimeMillis();
                }
                responseMsg = msgContext.getResponseMessage();
            } catch (AxisFault fault) {
                //log and sanitize
                processAxisFault(fault);
                configureResponseFromAxisFault(res, fault);
                responseMsg = msgContext.getResponseMessage();
                if (responseMsg == null) {
                    responseMsg = new Message(fault);
                    ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
                            getMessage().setMessageContext(msgContext);
                }
            } catch (Exception e) {
                //other exceptions are internal trouble
                responseMsg = msgContext.getResponseMessage();
                res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                responseMsg = convertExceptionToAxisFault(e, responseMsg);
                ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
                        getMessage().setMessageContext(msgContext);
            } catch (Throwable t) {
                logException(t);
                //other exceptions are internal trouble
                responseMsg = msgContext.getResponseMessage();
                res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                responseMsg = new Message(new AxisFault(t.toString(),t));
                ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
                        getMessage().setMessageContext(msgContext);
            }
        } catch (AxisFault fault) {
            processAxisFault(fault);
            configureResponseFromAxisFault(res, fault);
            responseMsg = msgContext.getResponseMessage();
            if (responseMsg == null) {
                responseMsg = new Message(fault);
                ((org.apache.axis.SOAPPart) responseMsg.getSOAPPart()).
                        getMessage().setMessageContext(msgContext);
            }
        }

        if (tlog.isDebugEnabled()) {
            t3 = System.currentTimeMillis();
        }

        /* Send response back along the wire...  */
        /***********************************/
        if (responseMsg != null) {
            // Transfer MIME headers to HTTP headers for response message.
            MimeHeaders responseMimeHeaders = responseMsg.getMimeHeaders();
            for (Iterator i = responseMimeHeaders.getAllHeaders(); i.hasNext(); ) {
                MimeHeader responseMimeHeader = (MimeHeader) i.next();
                res.addHeader(responseMimeHeader.getName(),
                              responseMimeHeader.getValue());
            }
            // synchronize the character encoding of request and response
            String responseEncoding = (String) msgContext.getProperty(
                    SOAPMessage.CHARACTER_SET_ENCODING);
            if (responseEncoding != null) {
                try {
                    responseMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING,
                                            responseEncoding);
                } catch (SOAPException e) {
                }
            }
            //determine content type from message response
            contentType = responseMsg.getContentType(msgContext.
                    getSOAPConstants());
            sendResponse(contentType, res, responseMsg);
        } else {
            // No content, so just indicate accepted
            res.setStatus(202);
        }
    }

doPost主要任务为:
1.构造MessageContext并进行初始化
  通过createMessageContext方法完成MessageContext构造,通过setProperty完成属性设置;
2.构造请求消息体
  通过Message requestMsg =new Message(req.getInputStream(),false,
         req.getHeader(HTTPConstants.HEADER_CONTENT_TYPE),
         req.getHeader(HTTPConstants.HEADER_CONTENT_LOCATION));
  完成;其构造方法依赖SOAPPart实例,并将请求输入流req.getInputStream()即:org.apache.catalina.connector.CoyoteInputStream(Tomcat环境)设置为SOAPPart的currentMessage;
3.AxisServer引擎调用
  通过invoke方法完成对各Handler链的一次调用;后面详细分析。
4.将处理完成的响应消息体发送至客户端。

AxisServer引擎invoke调用分析
public void invoke(MessageContext msgContext) throws AxisFault {
        String  hName = null ;
        Handler h     = null ;
        MessageContext previousContext = getCurrentMessageContext();
        try {
            setCurrentMessageContext(msgContext);
            hName = msgContext.getStrProp( MessageContext.ENGINE_HANDLER );
            if ( hName != null ) {
                if ( (h = getHandler(hName)) == null ) {
                    ClassLoader cl = msgContext.getClassLoader();
                    try {
                        log.debug( Messages.getMessage("tryingLoad00", hName) );
                        Class cls = ClassUtils.forName(hName, true, cl);
                        h = (Handler) cls.newInstance();
                    }
                    catch( Exception e ) {
                        h = null ;
                    }
                }
                if( tlog.isDebugEnabled() ) {
                    t1=System.currentTimeMillis();
                }
                if ( h != null )
                    h.invoke(msgContext);
                else
                    throw new AxisFault( "Server.error",
                                         Messages.getMessage("noHandler00", hName),
                                         null, null );
                }
                
            }
            else {
                hName = msgContext.getStrProp(MessageContext.TRANSPORT);
                if ( hName != null ) {
                if ((h = hr.find( hName )) != null ) {
                h.invoke(msgContext);
                } else {
                log.error(Messages.getMessage("noTransport02", hName));
                }
                } else {
                defaultTransport.invoke(msgContext);
                }
                //首先对server-config.wsdd中http传输协议配置的requestFlow
                   //handler进行处理,如:URLMapper、HTTPAuthHandler
                hName = msgContext.getTransportName();
                SimpleTargetedChain transportChain = null;
                if ( hName != null && (h = getTransport( hName )) != null ) {
                    if (h instanceof SimpleTargetedChain) {
                        transportChain = (SimpleTargetedChain)h;
                        h = transportChain.getRequestHandler();
                        if (h != null)
                            h.invoke(msgContext);
                    }
                }
                //处理全局请求handler chain
                if ((h = getGlobalRequest()) != null ) {
                    h.invoke(msgContext);
                }
                //处理所配置接口服务中的requestflow请求handler chain
                h = msgContext.getService();
                if (h == null) {
                    Message rm = msgContext.getRequestMessage();
                    rm.getSOAPEnvelope().getFirstBody();
                    
                    h = msgContext.getService();
                    if (h == null)
                        throw new AxisFault("Server.NoService",
                                            Messages.getMessage("noService05",
                                                                 "" + msgContext.getTargetService()),
                                            null, null );
                }
                initSOAPConstants(msgContext);
                try {
                    h.invoke(msgContext);
                } catch (AxisFault ae) {
                    if ((h = getGlobalRequest()) != null ) {
                        h.onFault(msgContext);
                    }
                    throw ae;
                }
                //处理全局响应handler chain
                if ((h = getGlobalResponse()) != null)
                    h.invoke(msgContext);
                //处理http传输的响应handler chain
                if (transportChain != null) {
                    h = transportChain.getResponseHandler();
                    if (h != null)
                        h.invoke(msgContext);
                }
            }
        } catch (AxisFault e) {
            throw e;
        } catch (Exception e) {
            // Should we even bother catching it ?
            throw AxisFault.makeFault(e);

        } finally {
            // restore previous state
            setCurrentMessageContext(previousContext);
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Exit: AxisServer::invoke");
        }
    }


通过以上代码可见、整个Axis引擎处理是通过一系列的handler chain进行invoke。其处理顺序为http requestFlow(URLMapper、HTTPAuthHandler)----global requestFlow(JWSHandler)----service requestFlow responseFlow(接口服务)
----global responseFlow----http responseFlow

那么依次分析各Handler处理过程。
一、transport配置Handler
1.org.apache.axis.handlers.http.URLMapper:
    public void invoke(MessageContext msgContext) throws AxisFault
    {
        log.debug("Enter: URLMapper::invoke");
        if ( msgContext.getService() == null ) {
            String path = (String)msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETPATHINFO);
            if ((path != null) && (path.length() >= 1)) { //rules out the cases of path="", path=null
            	if(path.startsWith("/"))
            		path = path.substring(1); 
                //设置此次请求目标服务
                msgContext.setTargetService( path );
            }
        }

        log.debug("Exit: URLMapper::invoke");
    }

URLMapper主要任务将客户端调用服务对应的SOAPService设置到MessageContext中
    public void setTargetService(String tServ) throws AxisFault {
        log.debug("MessageContext: setTargetService(" + tServ+")");

        if (tServ == null) {
            setService(null);
        }
        else {
            try {
                //首先从AxisEngine获取SOAPService服务
                   //通过SOAPService设置对应的MessageContext属性
                setService(getAxisEngine().getService(tServ));
            } catch (AxisFault fault) {
                // If we're on the client, don't throw this fault...
                if (!isClient()) {
                    throw fault;
                }
            }
        }
        targetService = tServ;
    }

AxisEngine:
    public SOAPService getService(String name) throws AxisFault
    {
        try {
            //委托至FileProvider返回SOAPService
            return config.getService(new QName(null, name));
        } catch (ConfigurationException e) {
            try {
                return config.getServiceByNamespaceURI(name);
            } catch (ConfigurationException e1) {
                throw new AxisFault(e);
            }
        }
    }


由于在初始化AxisServlet已经对server-config.wsdd配置进行实例化至WSDDDeployment中,并由FileProvider引用。
FileProvider实际上将getService任务交给deployment完成:
    public SOAPService getService(QName qname) throws ConfigurationException {
        SOAPService service = deployment.getService(qname);
        if (service == null) {
            throw new ConfigurationException(Messages.getMessage("noService10",
                                                           qname.toString()));
        }
        return service;
    }

deployment在AxisEngine初始化时已经持有server-config.wsdd中各种配置信息,如:transport、handler、globalConfiguration、service,并将各类配置存储至HashMap缓存中。
WSDDDeployment:
    public SOAPService getService(QName name) throws ConfigurationException {
        //从缓存中取出WSDDService
        WSDDService s = (WSDDService) services.get(name);
        if (s != null) {
            //通过WSDDService结构返回SOAPService实例
            return (SOAPService) s.getInstance(this);
        }
        return null;
    }

可见,deployment只是从存储service信息的HashMap(services)中取出WSDDServie实例(该实例在初始化时即WSDDDeployment构造函数中,已经对配置总所有service服务进行了注册),然后通过WSDDService返回SOAPService。WSDDService只是一种数据结构,用于保存service配置的属性信息;SOAPService是一种Handler,可参与整个Handler Chain中,并对MessageContext进行处理。
(SOAPService) s.getInstance(this)实现如下(实现类为:WSDDDeployableItem):
    public final Handler getInstance(EngineConfiguration registry)
        throws ConfigurationException
    {
        //是否为单态实例
        if (scope == SCOPE_SINGLETON) {
             synchronized (this) {
                if (singletonInstance == null)
                    singletonInstance = getNewInstance(registry);
            }
            return singletonInstance;
        }
        
        return getNewInstance(registry);
    }

    private Handler getNewInstance(EngineConfiguration registry)
        throws ConfigurationException
    {
        QName type = getType();
        if (type == null ||
            WSDDConstants.URI_WSDD_JAVA.equals(type.getNamespaceURI())) {
            //该任务交给具体子类完成
            return makeNewInstance(registry);
        } else {
            return registry.getHandler(type);
        }
    }

WSDDservice是WSDDDeployableItem的子类,WSDDservice的getInstance方法由父类WSDDDeployableItem完成。
WSDDservice-makeNewInstance:
public Handler makeNewInstance(EngineConfiguration registry)
        throws ConfigurationException
    {
        if (cachedService != null) {
            return cachedService;
        }

        // 初始化类型映射.
        initTMR();

        Handler reqHandler = null;
        //获取Service中配置的requestFlow Handler
        WSDDChain request = getRequestFlow();

        if (request != null) {
            //存在requestFlow时,返回对应的Handler
            //具体操作如WSDDService.getInstance方法
            reqHandler = request.getInstance(registry);
        }

        Handler providerHandler = null;

        if (providerQName != null) {
            try {
                //此处重要!!!在配置service时, 
                   //<service name="Version" provider="java:RPC">
                //其中的provider即为处理Messagecontext实现方式
                   //RPC:org.apache.axis.providers.java.RPCProvider
                providerHandler = WSDDProvider.getInstance(providerQName,this,registry);
            } catch (Exception e) {
                throw new ConfigurationException(e);
            }
            if (providerHandler == null)
                throw new WSDDException(
                          Messages.getMessage("couldntConstructProvider00"));
        }

        Handler respHandler = null;
        WSDDChain response = getResponseFlow();

        if (response != null) {
            //存在requestFlow时,返回对应的Handler
            respHandler = response.getInstance(registry);
        }
        //构造SOAPService实例,实际上SOAPService为SimpleTargetedChain子类
        SOAPService service = new SOAPService(reqHandler, providerHandler,respHandler);
        //设置SOAPService属性
        service.setStyle(style);
        service.setUse(use);
        service.setServiceDescription(desc);

        service.setHighFidelityRecording(!streaming);
        service.setSendType(sendType);

        if ( getQName() != null )
            service.setName(getQName().getLocalPart());
        service.setOptions(getParametersTable());

        service.setRoles(roles);

        service.setEngine(((WSDDDeployment)registry).getEngine());

        if (use != Use.ENCODED) {
            // If not encoded, turn off multi-refs and prefer
            // not to sent xsi:type and xsi:nil
            service.setOption(AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
            service.setOption(AxisEngine.PROP_SEND_XSI, Boolean.FALSE);
        }

        // Set handlerInfoChain
        if (_wsddHIchain != null) {
            HandlerInfoChainFactory hiChainFactory = _wsddHIchain.getHandlerChainFactory();

            service.setOption(Constants.ATTR_HANDLERINFOCHAIN, hiChainFactory);
        }

        AxisEngine.normaliseOptions(service);

        WSDDFaultFlow [] faultFlows = getFaultFlows();
        if (faultFlows != null && faultFlows.length > 0) {
            FaultableHandler wrapper = new FaultableHandler(service);
            for (int i = 0; i < faultFlows.length; i++) {
                WSDDFaultFlow flow = faultFlows[i];
                Handler faultHandler = flow.getInstance(registry);
                wrapper.setOption("fault-" + flow.getQName().getLocalPart(),
                                  faultHandler);
            }
        }

        try {
            service.getInitializedServiceDesc(MessageContext.getCurrentContext());
        } catch (AxisFault axisFault) {
            throw new ConfigurationException(axisFault);
        }

        cachedService = service;
        return service;
    }

至此,整个URLMapper的Handler已经处理完成。其重要任务就是将缓存中的service信息构造成SOAPService Handler,并设置到Messagecontext中。SOAPService实际上是个Handler Chain即:SimpleTargetedChain,该链中包含了service中配置的requestFlow、provider、responseFlow。当执行SOAPService的invoke方法时,通过配置依次执行handler。

2.org.apache.axis.handlers.http.HTTPAuthHandler:
    public void invoke(MessageContext msgContext) throws AxisFault
    {
        log.debug("Enter: HTTPAuthHandler::invoke");
        
        /* Process the Basic Auth stuff in the headers */
        /***********************************************/
        String tmp = (String)msgContext.getProperty(HTTPConstants.HEADER_AUTHORIZATION);
        if ( tmp != null ) tmp = tmp.trim();
        if ( tmp != null && tmp.startsWith("Basic ") ) {
            String user=null ;
            int  i ;

            tmp = new String( Base64.decode( tmp.substring(6) ) );
            i = tmp.indexOf( ':' );
            if ( i == -1 ) user = tmp ;
            else           user = tmp.substring( 0, i);
            msgContext.setUsername( user );
            log.debug( Messages.getMessage("httpUser00", user) );
            if ( i != -1 )  {
                String pwd = tmp.substring(i+1);
                if ( pwd != null && pwd.equals("") ) pwd = null ;
                if ( pwd != null ) {
                    msgContext.setPassword( pwd );
                    log.debug( Messages.getMessage("httpPassword00", pwd) );
                }
            }
        }

        log.debug("Exit: HTTPAuthHandler::invoke");
    }

HTTPAuthHandler主要是处理针对Basic验证方式的web应用,简单地将http请求中的用户名、密码信息设置到MessageContext中。

二、globalConfiguration配置handler
                //AxisServer中执行global invoke
                if ((h = getGlobalRequest()) != null ) {
                    h.invoke(msgContext);
                }

WSDDDeployment中的getGlobalRequest方法
    public Handler getGlobalRequest() throws ConfigurationException {
        if (globalConfig != null) {
            //取出当前requestFlow
            WSDDRequestFlow reqFlow = globalConfig.getRequestFlow();
            if (reqFlow != null)
                //返回Handler Chain
                return reqFlow.getInstance(this);
        }
        return null;
    }

WSDDRequestFlow中的makeNewInstance由父类WSDDChain实现
    public Handler makeNewInstance(EngineConfiguration registry)
        throws ConfigurationException
    {
        //new SimpleChain
        Chain c = new org.apache.axis.SimpleChain();
        
        for (int n = 0; n < handlers.size(); n++) {
            WSDDHandler handler = (WSDDHandler)handlers.get(n); 
            Handler h = handler.getInstance(registry);
            if ( h != null )
              //向chain中添加handler
              c.addHandler(h);
            else
              throw new ConfigurationException("……");
        }
        
        return c;
    }

org.apache.axis.handlers.JWSHandler
在上一篇中已经分析了JWSHandler的用途,主要是针对jws部署方式的处理。
由于JWS部署方式是没有service配置信息的,无法在WSDDDeployment缓存中获取,故通过JWSHandler进行特殊处理。
由于jws方式没有service信息,则通过这个handler完成SOAPService的构造。
            //先从jws的soapservices缓存中获取
            SOAPService rpc = (SOAPService)soapServices.get(clsName);
            if (rpc == null) {
                //构造SOAPService,provider为:RPCProvider
                rpc = new SOAPService(new RPCProvider());
                rpc.setName(clsName);
                rpc.setOption(RPCProvider.OPTION_CLASSNAME, clsName );
                rpc.setEngine(msgContext.getAxisEngine());
                String allowed = (String)getOption(RPCProvider.OPTION_ALLOWEDMETHODS);
                if (allowed == null) allowed = "*";
                rpc.setOption(RPCProvider.OPTION_ALLOWEDMETHODS, allowed);
                String scope = (String)getOption(RPCProvider.OPTION_SCOPE);
                if (scope == null) scope = Scope.DEFAULT.getName();
                rpc.setOption(RPCProvider.OPTION_SCOPE, scope);
                
                rpc.getInitializedServiceDesc(msgContext);
                //缓存当前SOAPService
                soapServices.put(clsName, rpc);                
            }
            rpc.setEngine(msgContext.getAxisEngine());
            
            rpc.init();   // ??
            msgContext.setService( rpc );



三、service配置handler
回到AxisServer中
                //将URLMapper 或者JWSHandler handler中设置的service取出
                h = msgContext.getService();
                if (h == null) {
                    Message rm = msgContext.getRequestMessage();
                    rm.getSOAPEnvelope().getFirstBody();
                    if (h == null)
                       ……;
                }
                if( tlog.isDebugEnabled() ) {
                    t3=System.currentTimeMillis();
                }
                //初始化soap信息
                   //比较复杂,通过sax解析request Inputstream。
                   //有空时再补充说明
                initSOAPConstants(msgContext);
                try {
                    //执行service handler chain,包含provider
                    h.invoke(msgContext);
                } catch (AxisFault ae) {
                    if ((h = getGlobalRequest()) != null ) {
                        h.onFault(msgContext);
                    }
                    throw ae;
                }

如果在service中配置了requestFlow,则先执行request handler 的invoke
如果部署的service未配置handler,则直接执行provider handler的invoke
RPCProvider是JavaProvider子类,其invoke由父类JavaProvider实现。
JavaProvider:
public void invoke(MessageContext msgContext) throws AxisFault {
        if (log.isDebugEnabled())
            log.debug("Enter: JavaProvider::invoke (" + this + ")");
        String serviceName = msgContext.getTargetService();
        Handler service = msgContext.getService();
        //service对应的类名
         //jws:即通过javac编译后加载的class类
         //wsdd:即通过className配置的class类
        String  clsName    = getServiceClassName(service);
        if ((clsName == null) || clsName.equals("")) {
            throw new AxisFault("Server.NoClassForService",
                Messages.getMessage("noOption00", getServiceClassNameOptionName(), serviceName),
                null, null);
        }

        IntHolder scope   = new IntHolder();
        Object serviceObject = null;

        try {
            //通过clsName新建service对应的class实例对象
              //未配置scope属性,则默认为request 生命周期
              //scope为session属性,则将该对象存储至session中
            serviceObject = getServiceObject(msgContext, service, clsName, scope);

            SOAPEnvelope   resEnv = null;
            OperationDesc operation = msgContext.getOperation();
            if (operation != null &&
                    OperationType.ONE_WAY.equals(operation.getMep())) {
                msgContext.setResponseMessage(null);
            } else {
                Message resMsg  = msgContext.getResponseMessage();

                if (resMsg == null) {
                    resEnv  = new SOAPEnvelope(msgContext.getSOAPConstants(),msgContext.getSchemaVersion());
                    //构造响应消息体response Message
                    resMsg = new Message(resEnv);
                    String encoding = XMLUtils.getEncoding(msgContext);
                    resMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
                    msgContext.setResponseMessage( resMsg );
                } else {
                    resEnv  = resMsg.getSOAPEnvelope();
                }
            }
            
            Message        reqMsg  = msgContext.getRequestMessage();
            SOAPEnvelope   reqEnv  = reqMsg.getSOAPEnvelope();
            //实际处理交给子类RPCProvider实现
            processMessage(msgContext, reqEnv, resEnv, serviceObject);
        } catch( SAXException exp ) {
            entLog.debug( Messages.getMessage("toAxisFault00"), exp);
            Exception real = exp.getException();
            if (real == null) {
                real = exp;
            }
            throw AxisFault.makeFault(real);
        } catch( Exception exp ) {
            entLog.debug( Messages.getMessage("toAxisFault00"), exp);
            AxisFault fault = AxisFault.makeFault(exp);
            //make a note if this was a runtime fault, for better logging
            if (exp instanceof RuntimeException) {
                fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION,
                        "true");
            }
            throw fault;
        } finally {
            // If this is a request scoped service object which implements
            // ServiceLifecycle, let it know that it's being destroyed now.
            if (serviceObject != null  &&
                scope.value == Scope.REQUEST.getValue() &&
                serviceObject instanceof ServiceLifecycle)
            {
                ((ServiceLifecycle)serviceObject).destroy();
            }
        }

        if (log.isDebugEnabled())
            log.debug("Exit: JavaProvider::invoke (" + this + ")");
    }


RPCProvider:
public void processMessage(MessageContext msgContext,
                               SOAPEnvelope reqEnv,
                               SOAPEnvelope resEnv,
                               Object obj)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Enter: RPCProvider.processMessage()");
        }

        SOAPService service = msgContext.getService();
        ServiceDesc serviceDesc = service.getServiceDescription();
        RPCElement body = getBody(reqEnv, msgContext);

        Vector args = null;
        try {
            args = body.getParams();
        } catch (SAXException e) {
            if(e.getException() != null)
                throw e.getException();
            throw e;
        }
        int numArgs = args.size();
        OperationDesc operation = getOperationDesc(msgContext, body);

        // Create the array we'll use to hold the actual parameter
        // values.  We know how big to make it from the metadata.
        Object[] argValues = new Object[operation.getNumParams()];

        // A place to keep track of the out params (INOUTs and OUTs)
        ArrayList outs = new ArrayList();

        // Put the values contained in the RPCParams into an array
        // suitable for passing to java.lang.reflect.Method.invoke()
        // Make sure we respect parameter ordering if we know about it
        // from metadata, and handle whatever conversions are necessary
        // (values -> Holders, etc)
        for (int i = 0; i < numArgs; i++) {
            RPCParam rpcParam = (RPCParam) args.get(i);
            Object value = rpcParam.getObjectValue();

            // first check the type on the paramter
            ParameterDesc paramDesc = rpcParam.getParamDesc();

            // if we found some type info try to make sure the value type is
            // correct.  For instance, if we deserialized a xsd:dateTime in
            // to a Calendar and the service takes a Date, we need to convert
            if (paramDesc != null && paramDesc.getJavaType() != null) {

                // Get the type in the signature (java type or its holder)
                Class sigType = paramDesc.getJavaType();

                // Convert the value into the expected type in the signature
                value = JavaUtils.convert(value, sigType);

                rpcParam.setObjectValue(value);
                if (paramDesc.getMode() == ParameterDesc.INOUT) {
                    outs.add(rpcParam);
                }
            }

            // Put the value (possibly converted) in the argument array
            // make sure to use the parameter order if we have it
            if (paramDesc == null || paramDesc.getOrder() == -1) {
                argValues[i] = value;
            } else {
                argValues[paramDesc.getOrder()] = value;
            }

            if (log.isDebugEnabled()) {
                log.debug("  " + Messages.getMessage("value00",
                        "" + argValues[i]));
            }
        }

        // See if any subclasses want a crack at faulting on a bad operation
        // FIXME : Does this make sense here???
        String allowedMethods = (String) service.getOption("allowedMethods");
        checkMethodName(msgContext, allowedMethods, operation.getName());

        // Now create any out holders we need to pass in
        int count = numArgs;
        for (int i = 0; i < argValues.length; i++) {

            // We are interested only in OUT/INOUT
            ParameterDesc param = operation.getParameter(i);
            if(param.getMode() == ParameterDesc.IN)
                continue;

            Class holderClass = param.getJavaType();
            if (holderClass != null &&
                    Holder.class.isAssignableFrom(holderClass)) {
                int index = count;
                // Use the parameter order if specified or just stick them to the end.
                if (param.getOrder() != -1) {
                    index = param.getOrder();
                } else {
                    count++;
                }
                // If it's already filled, don't muck with it
                if (argValues[index] != null) {
                    continue;
                }
                argValues[index] = holderClass.newInstance();
                // Store an RPCParam in the outs collection so we
                // have an easy and consistent way to write these
                // back to the client below
                RPCParam p = new RPCParam(param.getQName(),
                        argValues[index]);
                p.setParamDesc(param);
                outs.add(p);
            } else {
                throw new AxisFault(Messages.getMessage("badOutParameter00",
                        "" + param.getQName(),
                        operation.getName()));
            }
        }

        // OK!  Now we can invoke the method
        Object objRes = null;
        try {
            //该方法完成服务调用
              //即通过反射调用执行service中className、以及客户端指定的operation指定的操作名称
              //obj:className所对应的实例
              //argValues:操作方法包含的参数
            objRes = invokeMethod(msgContext,
                                  operation.getMethod(),
                                  obj, argValues);
        } catch (IllegalArgumentException e) {
            String methodSig = operation.getMethod().toString();
            String argClasses = "";
            for (int i = 0; i < argValues.length; i++) {
                if (argValues[i] == null) {
                    argClasses += "null";
                } else {
                    argClasses += argValues[i].getClass().getName();
                }
                if (i + 1 < argValues.length) {
                    argClasses += ",";
                }
            }
            log.info(Messages.getMessage("dispatchIAE00",
                    new String[]{methodSig, argClasses}),
                    e);
            throw new AxisFault(Messages.getMessage("dispatchIAE00",
                    new String[]{methodSig, argClasses}),
                    e);
        }

        /** If this is a one-way operation, there is nothing more to do.
         */
        if (OperationType.ONE_WAY.equals(operation.getMep()))
            return;
        //根据返回值构造响应消息体
        RPCElement resBody = createResponseBody(body, msgContext, operation, serviceDesc, objRes, resEnv, outs);
        resEnv.addBodyElement(resBody);
    }

由于时间问题,后面部分分析的比较粗糙
希望以后看到这个,还能记得。

你可能感兴趣的:(apache,数据结构,tomcat,SOAP,化工)