Axis源码分析-Web服务部署(二)

1.服务部署:
1)即时发布
编写java类,去掉包名称,将.java文件类型改成jws。
通过浏览器打开url如:http://localhost:8888/axis/EchoHeaders.jws
点击“Click to see the WSDL”,即可查看所部署服务的WSDL描述文件

2)定制发布
通过deploy.wsdd部署,如:
  <service name="AxisService" provider="java:RPC">
  <parameter name="allowedMethods" value="*"/>
  <parameter name="className" value="com.axis.service.AxisService"/>
</service>

2.源码解读:
1)初始化AxisEngine:
  <servlet>
    <servlet-name>AxisServlet</servlet-name>
    <display-name>Apache-Axis Servlet</display-name>
    <servlet-class>
        org.apache.axis.transport.http.AxisServlet
    </servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>*.jws</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>

即所有以jws结尾或者services路径的的URL均由AxisServlet进行处理。
AxisServlet的init方法:
public void init() throws javax.servlet.ServletException {
        //super.init()即执行父类AxisServletBase的init方法,完成AxisServer初始化工作
        super.init();
        ServletContext context = getServletConfig().getServletContext();
        isDebug = log.isDebugEnabled();
        if (isDebug) {
            log.debug("In servlet init");
        }
        transportName = getOption(context,
                                  INIT_PROPERTY_TRANSPORT_NAME,
HTTPTransport.DEFAULT_TRANSPORT_NAME);
        if (JavaUtils.isTrueExplicitly(getOption(context,
INIT_PROPERTY_USE_SECURITY, null))) {
            securityProvider = new ServletSecurityProvider();
        }

        enableList =
                JavaUtils.isTrueExplicitly(getOption(context,
                INIT_PROPERTY_ENABLE_LIST, null));

        jwsClassDir = getOption(context, INIT_PROPERTY_JWS_CLASS_DIR, null);

        disableServicesList = JavaUtils.isTrue(getOption(context,
                INIT_PROPERTY_DISABLE_SERVICES_LIST, "false"));

        servicesPath = getOption(context, INIT_PROPERTY_SERVICES_PATH,
                                 "/services/");

        if (jwsClassDir != null) {
            if (getHomeDir() != null) {
                jwsClassDir = getHomeDir() + jwsClassDir;
            }
        } else {
            jwsClassDir = getDefaultJWSClassDir();
        }
        //初始化查询Handler,即wsdl对应的handler,用于wsdl文件生成
        initQueryStringHandlers();

        // Setup the service admin
        try {
            ServiceAdmin.setEngine(this.getEngine(), context.getServerInfo());
        } catch (AxisFault af) {
            exceptionLog.info("Exception setting AxisEngine on ServiceAdmin " +
                              af);
        }
    }

AxisServletBase.init():
    public void init() throws javax.servlet.ServletException {
        ServletContext context = getServletConfig().getServletContext();
        webInfPath = context.getRealPath("/WEB-INF");
        homeDir = context.getRealPath("/");
        isDebug = log.isDebugEnabled();
        if(log.isDebugEnabled()) log.debug("In AxisServletBase init");
        //触发AxisServer的初始化
        isDevelopment= JavaUtils.isTrueExplicitly(getOption(context,
                        INIT_PROPERTY_DEVELOPMENT_SYSTEM, null));
    }

AxisServer初始化工作由getOption触发
    protected String getOption(ServletContext context,
                             String param,
                             String dephault)
    {
        String value = AxisProperties.getProperty(param);
        if (value == null)
            value = getInitParameter(param);

        if (value == null)
            value = context.getInitParameter(param);
        try {
            //初始化AxisServer
            AxisServer engine = getEngine(this);
            if (value == null && engine != null)
                value = (String) engine.getOption(param);
        } catch (AxisFault axisFault) {
        }
        return (value != null) ? value : dephault;
    }

初始化AxisServer:
    public static AxisServer getEngine(HttpServlet servlet) throws AxisFault
    {
        AxisServer engine = null;
        if (isDebug)
            log.debug("Enter: getEngine()");
        ServletContext context = servlet.getServletContext();
        synchronized (context) {
            engine = retrieveEngine(servlet);
            if (engine == null) {
                //配置Engine环境
                Map environment = getEngineEnvironment(servlet);
                //初始化AxisServer Engine
                engine = AxisServer.getServer(environment);
                engine.setName(servlet.getServletName());
                //存储AxisServer Engine至上下文
                storeEngine(servlet, engine);
            }
        }
        if (isDebug)
            log.debug("Exit: getEngine()");
        return engine;
    }

首先从当前上下文中获取AxisServer Engine,如果返回为null,则进行初始化并存储至上下文中。
    protected static Map getEngineEnvironment(HttpServlet servlet) {
        Map environment = new HashMap();

        String attdir= servlet.getInitParameter(AxisEngine.ENV_ATTACHMENT_DIR);
        if (attdir != null)
            environment.put(AxisEngine.ENV_ATTACHMENT_DIR, attdir);

        ServletContext context = servlet.getServletContext();
        environment.put(AxisEngine.ENV_SERVLET_CONTEXT, context);

        String webInfPath = context.getRealPath("/WEB-INF");
        if (webInfPath != null)
            environment.put(AxisEngine.ENV_SERVLET_REALPATH,
                            webInfPath + File.separator + "attachments");

        EngineConfiguration config =
            EngineConfigurationFactoryFinder.newFactory(servlet)
                    .getServerEngineConfig();

        if (config != null) {
            environment.put(EngineConfiguration.PROPERTY_NAME, config);
        }

        return environment;
    }

EngineConfigurationFactoryFinder.newFactory(servlet)返回org.apache.axis.configuration.EngineConfigurationFactoryServlet工厂实例,并通过private static EngineConfiguration getServerEngineConfig(ServletConfig cfg)新建EngineConfiguration实现类:FileProvider对象(即server-config.wsdd的文件操作类)

AxisServer类getServer方法充当工厂方法,返回自身对象。但实际新建AxisServer Engine任务是委托AxisServerFactory工厂实例完成。
    public static AxisServer getServer(Map environment) throws AxisFault
    {
        if (factory == null) {
            String factoryClassName = AxisProperties.getProperty("axis.ServerFactory");
            if (factoryClassName != null) {
                try {
                    Class factoryClass = ClassUtils.forName(factoryClassName);
                    if (AxisServerFactory.class.isAssignableFrom(factoryClass))
                        factory = (AxisServerFactory)factoryClass.newInstance();
                } catch (Exception e) {
                    // If something goes wrong here, should we just fall
                    // through and use the default one?
                    log.error(Messages.getMessage("exception00"), e);
                }
            }
            
            if (factory == null) {
                //通过默认工厂新建Server Engine
                factory = new DefaultAxisServerFactory();
            }
        }
        return factory.getServer(environment);                
    }

DefaultAxisServerFactory类getServer方法:
    public AxisServer getServer(Map environment) throws AxisFault {
        log.debug("Enter: DefaultAxisServerFactory::getServer");

        AxisServer ret = createServer(environment);

        if (ret != null) {
            if (environment != null) {
                ret.setOptionDefault(AxisEngine.PROP_ATTACHMENT_DIR,
                    (String)environment.get(AxisEngine.ENV_ATTACHMENT_DIR));

                ret.setOptionDefault(AxisEngine.PROP_ATTACHMENT_DIR,
                    (String)environment.get(AxisEngine.ENV_SERVLET_REALPATH));
            }

            String attachmentsdir = (String)ret.getOption(AxisEngine.PROP_ATTACHMENT_DIR);

            if (attachmentsdir != null) {
                File attdirFile = new File(attachmentsdir);
                if (!attdirFile.isDirectory()) {
                    attdirFile.mkdirs();
                }
            }
        }

        log.debug("Exit: DefaultAxisServerFactory::getServer");

        return ret;
    }

    private static AxisServer createServer(Map environment) {
        //从Map环境中取出FileProvider对象
        EngineConfiguration config = getEngineConfiguration(environment);
        //通过AxisServer(EngineConfiguration config)构造函数新建对象
        return (config == null) ? new AxisServer() : new AxisServer(config);
    }


    public AxisServer(EngineConfiguration config)
    {
        //Engine的初始化由父类AxisEngine完成
        super(config);
        // 服务端默认是保存配置
        setShouldSaveConfig(true);
    }


public void init() {
        if (log.isDebugEnabled()) {
            log.debug("Enter: AxisEngine::init");
        }
        try {
            //通过FileProvider类配置Engine
            config.configureEngine(this);
        } catch (Exception e) {
            throw new InternalException(e);
        }
        setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION,
                         AxisProperties.getProperty("axis." + PROP_ATTACHMENT_IMPLEMENTATION  ));

        setOptionDefault(PROP_ATTACHMENT_IMPLEMENTATION, DEFAULT_ATTACHMENT_IMPL);
        final Object dotnet = getOption(PROP_DOTNET_SOAPENC_FIX);
        if (JavaUtils.isTrue(dotnet)) {
            TypeMappingImpl.dotnet_soapenc_bugfix = true;
        }

        if (log.isDebugEnabled()) {
            log.debug("Exit: AxisEngine::init");
        }

    }

public void configureEngine(AxisEngine engine)
        throws ConfigurationException {
        try {
            if (getInputStream() == null) {
                try {
                    setInputStream(new FileInputStream(configFile));
                } catch (Exception e) {
                    if (searchClasspath)
                        setInputStream(ClassUtils.getResourceAsStream(engine.getClass(), filename, true));
                }
            }

            if (getInputStream() == null) {
                throw new ConfigurationException(
                        Messages.getMessage("noConfigFile"));
            }
            //初始化deployment
            WSDDDocument doc = new WSDDDocument(XMLUtils.
                                                newDocument(getInputStream()));
            deployment = doc.getDeployment();
            //deployment持有Engine引用
            deployment.configureEngine(engine);
            //刷新global配置选项
            engine.refreshGlobalOptions();

            setInputStream(null);
        } catch (Exception e) {
            throw new ConfigurationException(e);
        }
    }

configureEngine完成的任务主要是解析server-config.wsdd服务配置。将配置文件中的各种属性(handler、globalConfiguration、service、transport……)缓存至WSDDDeployment类中。刷新global配置选项即将server-config.wsdd配置文件中globalConfiguration节点中的parameter属性集合由AxisEngine持有。

以上完成了所有初始化工作。

2)通过url打开服务:
在浏览器中打开
http://localhost:8888/axis/EchoHeaders.jws
AxisServlet的doGet方法:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (isDebug) {
            log.debug("Enter: doGet()");
        }
        PrintWriter writer = new FilterPrintWriter(response);

        try {
            AxisEngine engine = getEngine();
            ServletContext servletContext =
                    getServletConfig().getServletContext();

            String pathInfo = request.getPathInfo();
            String realpath = servletContext.getRealPath(request.getServletPath());
            if (realpath == null) {
                realpath = request.getServletPath();
            }
            boolean isJWSPage = request.getRequestURI().endsWith(".jws");
            if (isJWSPage) {
                pathInfo = request.getServletPath();
            }
            //判断是否存在查询。即server-config.wsdd的transport节点
              //配置的parameter查询条件(list/method/wsdl)
            //如url:http://localhost:8888/axis/EchoHeaders.jws?wsdl
            //如url:http://localhost:8888/services/AxisService?wsdl
            //这样doGet直接生成wsdl描述信息至浏览器端
            if (processQuery(request, response, writer) == true) {
                return;
            }
            boolean hasNoPath = (pathInfo == null || pathInfo.equals(""));
            if (!disableServicesList) {
                if(hasNoPath) {
                    reportAvailableServices(response, writer, request);
                } else if (realpath != null) {
                    MessageContext msgContext = createMessageContext(engine,request, response);
                    String url = HttpUtils.getRequestURL(request).toString();

                    msgContext.setProperty(MessageContext.TRANS_URL, url);
                    String serviceName;
                    if (pathInfo.startsWith("/")) {
                        serviceName = pathInfo.substring(1);
                    } else {
                        serviceName = pathInfo;
                    }
                    //从WSDDDeployment的services缓存中取service
                    SOAPService s = engine.getService(serviceName);
                    if (s == null) {
                        if (isJWSPage) {
                            //生成Click to see the WSDL连接的页面
                                reportCantGetJWSService(request, response, writer);
                        } else {
                            reportCantGetAxisService(request, response, writer);
                        }

                    } else {
                        reportServiceInfo(response, writer, s, serviceName);
                    }
                }
            } else {
                response.setContentType("text/html; charset=utf-8");
                writer.println("<html><h1>Axis HTTP Servlet</h1>");
                writer.println(Messages.getMessage("reachedServlet00"));
                writer.println("<p>" +
                               Messages.getMessage("transportName00",
                        "<b>" + transportName + "</b>"));
                writer.println("</html>");
            }
        } catch (AxisFault fault) {
            reportTroubleInGet(fault, response, writer);
        } catch (Exception e) {
            reportTroubleInGet(e, response, writer);
        } finally {
            writer.close();
            if (isDebug) {
                log.debug("Exit: doGet()");
            }
        }
    }


如果是JWS服务,在返回的页面中,点击“Click to see the WSDL”,则产生服务描述XML信息。
该链接对应的url为:http://localhost:8888/axis/EchoHeaders.jws?wsdl
即带有查询条件的url。
上面代码注释中已说明此类url由processQuery(request, response, writer)处理
private boolean processQuery(HttpServletRequest request,
                                 HttpServletResponse response,
                                 PrintWriter writer) throws AxisFault {
        String path = request.getServletPath();
        String queryString = request.getQueryString();
        String serviceName;
        AxisEngine engine = getEngine();
        Iterator i = this.transport.getOptions().keySet().iterator();

        if (queryString == null) {
            return false;
        }

        String servletURI = request.getContextPath() + path;
        String reqURI = request.getRequestURI();
        // chop off '/'.
        if (servletURI.length() + 1 < reqURI.length()) {
            serviceName = reqURI.substring(servletURI.length() + 1);
        } else {
            serviceName = "";
        } while (i.hasNext() == true) {
            String queryHandler = (String) i.next();
            if (queryHandler.startsWith("qs.") == true) {
                String handlerName = queryHandler.substring
                                     (queryHandler.indexOf(".") + 1).
                                     toLowerCase();
                int length = 0;
                boolean firstParamFound = false;

                while (firstParamFound == false && length < queryString.length()) {
                    char ch = queryString.charAt(length++);

                    if (ch == '&' || ch == '=') {
                        firstParamFound = true;

                        --length;
                    }
                }
                if (length < queryString.length()) {
                    queryString = queryString.substring(0, length);
                }
                if (queryString.toLowerCase().equals(handlerName) == true) {
                    if (this.transport.getOption(queryHandler).equals("")) {
                        return false;
                    }

                    try {
                        MessageContext msgContext = createMessageContext(engine,request, response);
                        Class plugin = Class.forName((String)this.transport.getOption(queryHandler));
                        Method pluginMethod = plugin.getDeclaredMethod("invoke",new Class[] {msgContext.getClass()});
                        String url = HttpUtils.getRequestURL(request).toString();
                        msgContext.setProperty(MessageContext.TRANS_URL, url);
                        msgContext.setProperty(HTTPConstants.
                               PLUGIN_SERVICE_NAME, serviceName);
                        msgContext.setProperty(HTTPConstants.PLUGIN_NAME,handlerName);
                        msgContext.setProperty(HTTPConstants.
                            PLUGIN_IS_DEVELOPMENT,
                            new Boolean(isDevelopment()));
                        msgContext.setProperty(HTTPConstants.PLUGIN_ENABLE_LIST,new Boolean(enableList));
                        msgContext.setProperty(HTTPConstants.PLUGIN_ENGINE,engine);
                        msgContext.setProperty(HTTPConstants.PLUGIN_WRITER,writer);
                        msgContext.setProperty(HTTPConstants.PLUGIN_LOG, log);
                        msgContext.setProperty(HTTPConstants.
                         PLUGIN_EXCEPTION_LOG,exceptionLog);
                        pluginMethod.invoke(plugin.newInstance(),
                         new Object[] {msgContext});
                        writer.close();
                        return true;
                    } catch (InvocationTargetException ie) {
                        reportTroubleInGet(ie.getTargetException(), response,writer);
                        return true;
                    } catch (Exception e) {
                        reportTroubleInGet(e, response, writer);
                        return true;
                    }
                }
            }
        }

        return false;
    }

以上代码主要任务是根据查询条件字符串(即wsdl),通过与server-config.wsdd中transport节点parameter属性匹配,查找对应的handler(即:org.apache.axis.transport.http.QSWSDLHandler)。并通过反射执行QSWSDLHandler的invoke方法
QSWSDLHandler:
    public void invoke(MessageContext msgContext) throws AxisFault {
        // Obtain objects relevant to the task at hand from the provided
        // MessageContext's bag.
        configureFromContext(msgContext);
        AxisServer engine = (AxisServer) msgContext.getProperty
                (HTTPConstants.PLUGIN_ENGINE);
        PrintWriter writer = (PrintWriter) msgContext.getProperty
                (HTTPConstants.PLUGIN_WRITER);
        HttpServletResponse response = (HttpServletResponse)
                msgContext.getProperty(HTTPConstants.MC_HTTP_SERVLETRESPONSE);
        try {
            //生成WSDL服务描述信息
            engine.generateWSDL(msgContext);
            Document wsdlDoc = (Document) msgContext.getProperty("WSDL");
            if (wsdlDoc != null) {
                try {
                    updateSoapAddressLocationURLs(wsdlDoc, msgContext);
                } catch (RuntimeException re) {
                    log.warn(
                            "Failed to update soap:address location URL(s) in WSDL.",
                            re);
                }
                response.setContentType(
                        "text/xml; charset=" +
                        XMLUtils.getEncoding().toLowerCase());
                //将描述信息XML通过writer输出至浏览器端
                reportWSDL(wsdlDoc, writer);
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("processWsdlRequest: failed to create WSDL");
                }
                reportNoWSDL(response, writer, "noWSDL02", null);
            }
        } catch (AxisFault axisFault) {
            //the no-service fault is mapped to a no-wsdl error
            if (axisFault.getFaultCode().equals
                    (Constants.QNAME_NO_SERVICE_FAULT_CODE)) {
                //which we log
                processAxisFault(axisFault);

                //then report under a 404 error
                response.setStatus(HttpURLConnection.HTTP_NOT_FOUND);
                reportNoWSDL(response, writer, "noWSDL01", axisFault);
            } else {
                //all other faults get thrown
                throw axisFault;
            }
        }
    }

AxisEngine的generateWSDL方法:
    public void generateWSDL(MessageContext msgContext) throws AxisFault {
        if (log.isDebugEnabled()) {
            log.debug("Enter: AxisServer::generateWSDL");
        }

        if (!isRunning()) {
            throw new AxisFault("Server.disabled",
                                Messages.getMessage("serverDisabled00"),
                                null, null);
        }

        String  hName = null ;
        Handler h     = null ;

        // save previous context
        MessageContext previousContext = getCurrentMessageContext();

        try {
            // set active context
            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 ) {
                        throw new AxisFault(
                                "Server.error",
                                Messages.getMessage("noHandler00", hName),
                                null, null );
                    }
                }
                h.generateWSDL(msgContext);
            }
            else {
                hName = msgContext.getStrProp(MessageContext.TRANSPORT);
                if ( hName != null ) {
                if ((h = hr.find( hName )) != null ) {
                h.generateWSDL(msgContext);
                } else {
                log.error(Messages.getMessage("noTransport02", hName));
                }
                } else {
                defaultTransport.generateWSDL(msgContext);
                }
                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.generateWSDL(msgContext);
                        }
                    }
                }

                if ((h = getGlobalRequest()) != null )
                    h.generateWSDL(msgContext);

                h = msgContext.getService();
                if (h == null) {
                    Message rm = msgContext.getRequestMessage();
                    if (rm != null) {
                        rm.getSOAPEnvelope().getFirstBody();
                        h = msgContext.getService();
                    }
                    if (h == null) {
                    ……
                    }
                }

                h.generateWSDL(msgContext);
                if ((h = getGlobalResponse()) != null )
                    h.generateWSDL(msgContext);
                if (transportChain != null) {
                    h = transportChain.getResponseHandler();
                    if (h != null) {
                        h.generateWSDL(msgContext);
                    }
                }
            }
        } catch (AxisFault e) {
            throw e;
        } catch(Exception e) {
            throw AxisFault.makeFault(e);
        } finally {
            setCurrentMessageContext(previousContext);
        }
    }

以上代码主要将生成wsdl任务交给server-config.wsdd所配置的一系列Handler,其执行顺序为
transport【requestFlow】---->globalConfiguration【requestFlow】---->service【requestFlow】---->service【responseFlow】---->globalConfiguration【responseFlow】---->transport【responseFlow】
针对jws的服务通过JWSHandler处理
org.apache.axis.handlers.JWSHandler:
    public void generateWSDL(MessageContext msgContext) throws AxisFault {
        try {
            setupService(msgContext);
        } catch (Exception e) {
            log.error( Messages.getMessage("exception00"), e );
            throw AxisFault.makeFault(e);
        }
    }

    protected void setupService(MessageContext msgContext) throws Exception {
        // FORCE the targetService to be JWS if the URL is right.
        String realpath = msgContext.getStrProp(Constants.MC_REALPATH);
        String extension = (String)getOption(OPTION_JWS_FILE_EXTENSION);
        if (extension == null) extension = DEFAULT_JWS_FILE_EXTENSION;
        
        if ((realpath!=null) && (realpath.endsWith(extension))) {
            /* Grab the *.jws filename from the context - should have been */
            /* placed there by another handler (ie. HTTPActionHandler)     */
            /***************************************************************/
            String   jwsFile = realpath;
            String rel = msgContext.getStrProp(Constants.MC_RELATIVE_PATH);

            // Check for file existance, report error with
            // relative path to avoid giving out directory info.
            File  f2 = new File( jwsFile );
            if (!f2.exists()) {
                throw new FileNotFoundException(rel);
            }

            if (rel.charAt(0) == '/') {
                rel = rel.substring(1);
            }

            int lastSlash = rel.lastIndexOf('/');
            String dir = null;
            
            if (lastSlash > 0) {
                dir = rel.substring(0, lastSlash);
            }
            
            String file = rel.substring(lastSlash + 1);
            
            String outdir = msgContext.getStrProp( Constants.MC_JWS_CLASSDIR );
            if ( outdir == null ) outdir = "." ;
            
            // Build matching directory structure under the output
            // directory.  In other words, if we have:
            //    /webroot/jws1/Foo.jws
            //
            // That will be compiled to:
            //    .../jwsOutputDirectory/jws1/Foo.class
            if (dir != null) {
                outdir = outdir + File.separator + dir;
            }
            
            // Confirm output directory exists.  If not, create it IF we're
            // allowed to.
            // !!! TODO: add a switch to control this.
            File outDirectory = new File(outdir);
            if (!outDirectory.exists()) {
                outDirectory.mkdirs();
            }
            
            if (log.isDebugEnabled())
                log.debug("jwsFile: " + jwsFile );
            
            String   jFile   = outdir + File.separator + file.substring(0, file.length()-extension.length()+1) +
                    "java" ;
            String   cFile   = outdir + File.separator + file.substring(0, file.length()-extension.length()+1) +
                    "class" ;
            
            if (log.isDebugEnabled()) {
                log.debug("jFile: " + jFile );
                log.debug("cFile: " + cFile );
                log.debug("outdir: " + outdir);
            }
            
            File  f1 = new File( cFile );

            /* Get the class */
            /*****************/
            String clsName = null ;
            //clsName = msgContext.getStrProp(Constants.MC_RELATIVE_PATH);
            if ( clsName == null ) clsName = f2.getName();
            if ( clsName != null && clsName.charAt(0) == '/' )
                clsName = clsName.substring(1);
            
            clsName = clsName.substring( 0, clsName.length()-extension.length() );
            clsName = clsName.replace('/', '.');
            
            if (log.isDebugEnabled())
                log.debug("ClsName: " + clsName );
            
            /* Check to see if we need to recompile */
            /****************************************/
            if ( !f1.exists() || f2.lastModified() > f1.lastModified() ) {
                /* If the class file doesn't exist, or it's older than the */
                /* java file then recompile the java file.                 */
                /* Start by copying the *.jws file to *.java               */
                /***********************************************************/
                log.debug(Messages.getMessage("compiling00", jwsFile) );
                log.debug(Messages.getMessage("copy00", jwsFile, jFile) );
                FileReader fr = new FileReader( jwsFile );
                FileWriter fw = new FileWriter( jFile );
                char[] buf = new char[4096];
                int    rc ;
                while ( (rc = fr.read( buf, 0, 4095)) >= 0 )
                    fw.write( buf, 0, rc );
                fw.close();
                fr.close();
                
                /* Now run javac on the *.java file */
                /************************************/
                log.debug("javac " + jFile );
                // Process proc = rt.exec( "javac " + jFile );
                // proc.waitFor();
                //获取编译器(默认:sun.tools.javac.Main,com.sun.tools.javac.main.Main)
                Compiler          compiler = CompilerFactory.getCompiler();
                
                compiler.setClasspath(ClasspathUtils.getDefaultClasspath(msgContext));
                compiler.setDestination(outdir);
                compiler.addFile(jFile);
                
                boolean result   = compiler.compile();
                
                /* Delete the temporary *.java file and check return code */
                /**********************************************************/
                (new File(jFile)).delete();
                
                if ( !result ) {
                    /* Delete the *class file - sometimes it gets created even */
                    /* when there are errors - so erase it so it doesn't       */
                    /* confuse us.                                             */
                    /***********************************************************/
                    (new File(cFile)).delete();
                    
                    Document doc = XMLUtils.newDocument();
                    
                    Element         root = doc.createElementNS("", "Errors");
                    StringBuffer message = new StringBuffer("Error compiling ");
                    message.append(jFile);
                    message.append(":\n");
                    
                    List errors = compiler.getErrors();
                    int count = errors.size();
                    for (int i = 0; i < count; i++) {
                        CompilerError error = (CompilerError) errors.get(i);
                        if (i > 0) message.append("\n");
                        message.append("Line ");
                        message.append(error.getStartLine());
                        message.append(", column ");
                        message.append(error.getStartColumn());
                        message.append(": ");
                        message.append(error.getMessage());
                    }
                    root.appendChild( doc.createTextNode( message.toString() ) );
                    throw new AxisFault( "Server.compileError",
                                         Messages.getMessage("badCompile00", jFile),
                                         null, new Element[] { root } );
                }
                ClassUtils.removeClassLoader( clsName );
                // And clean out the cached service.
                soapServices.remove(clsName);
            }
            
            ClassLoader cl = ClassUtils.getClassLoader(clsName);
            if (cl == null) {
                cl = new JWSClassLoader(clsName,
                                        msgContext.getClassLoader(),
                                        cFile);
            }
            
            msgContext.setClassLoader(cl);
            
            /* Create a new RPCProvider - this will be the "service"   */
            /* that we invoke.                                                */
            /******************************************************************/
            // Cache the rpc service created to handle the class.  The cache
            // is based on class name, so only one .jws/.jwr class can be active
            // in the system at a time.
            SOAPService rpc = (SOAPService)soapServices.get(clsName);
            if (rpc == null) {
                rpc = new SOAPService(new RPCProvider());
                rpc.setName(clsName);
                rpc.setOption(RPCProvider.OPTION_CLASSNAME, clsName );
                rpc.setEngine(msgContext.getAxisEngine());
                
                // Support specification of "allowedMethods" as a parameter.
                String allowed = (String)getOption(RPCProvider.OPTION_ALLOWEDMETHODS);
                if (allowed == null) allowed = "*";
                rpc.setOption(RPCProvider.OPTION_ALLOWEDMETHODS, allowed);
                // Take the setting for the scope option from the handler
                // parameter named "scope"
                String scope = (String)getOption(RPCProvider.OPTION_SCOPE);
                if (scope == null) scope = Scope.DEFAULT.getName();
                rpc.setOption(RPCProvider.OPTION_SCOPE, scope);
                
                rpc.getInitializedServiceDesc(msgContext);
                
                soapServices.put(clsName, rpc);                
            }
            
            // Set engine, which hooks up type mappings.
            rpc.setEngine(msgContext.getAxisEngine());
            
            rpc.init();   // ??

            // OK, this is now the destination service!
            msgContext.setService( rpc );
        }

        if (log.isDebugEnabled()) {
            log.debug("Exit: JWSHandler::invoke");
        }
    }

以上代码主要完成将jws转换成java文件,并临时存放至jwsClasses目录中,再通过jdk中的编译器sun.tools.javac.Main、com.sun.tools.javac.main.Main对java文件进行编译,将编译后的class文件存放至jwsClasses目录中,删除临时java文件,并将生成的class二进制文件加载至类加载器中。
rpc = new SOAPService(new RPCProvider());
增加Handler实例RPCProvider(继承BasicProvider)到当前handler链中
BasicProvider generateWSDL:
public void generateWSDL(MessageContext msgContext) throws AxisFault {
        if (log.isDebugEnabled())
            log.debug("Enter: BasicProvider::generateWSDL (" + this +")");

        SOAPService service = msgContext.getService();
        
        ServiceDesc serviceDesc = service.getInitializedServiceDesc(msgContext);

        try {
            // Location URL is whatever is explicitly set in the MC
            String locationUrl = msgContext.getStrProp(MessageContext.WSDLGEN_SERV_LOC_URL);

            if (locationUrl == null) {
                // If nothing, try what's explicitly set in the ServiceDesc
                locationUrl = serviceDesc.getEndpointURL();
            }

            if (locationUrl == null) {
                // If nothing, use the actual transport URL
                locationUrl = msgContext.getStrProp(MessageContext.TRANS_URL);
            }

            // Interface namespace is whatever is explicitly set
            String interfaceNamespace = msgContext.getStrProp(MessageContext.WSDLGEN_INTFNAMESPACE);

            if (interfaceNamespace == null) {
                // If nothing, use the default namespace of the ServiceDesc
                interfaceNamespace = serviceDesc.getDefaultNamespace();
            }

            if (interfaceNamespace == null) {
                // If nothing still, use the location URL determined above
                interfaceNamespace = locationUrl;
            }

            Emitter emitter = new Emitter();

            String alias = (String) service.getOption("alias");
            if (alias != null)
                emitter.setServiceElementName(alias);

            // Set style/use
            emitter.setStyle(serviceDesc.getStyle());
            emitter.setUse(serviceDesc.getUse());

            if (serviceDesc instanceof JavaServiceDesc) {
                emitter.setClsSmart(((JavaServiceDesc)serviceDesc).getImplClass(),
                                    locationUrl);
            }

            // If a wsdl target namespace was provided, use the targetNamespace.
            // Otherwise use the interfaceNamespace constructed above.
            String targetNamespace = (String) service.getOption(OPTION_WSDL_TARGETNAMESPACE);
            if (targetNamespace == null || targetNamespace.length() == 0) {
                targetNamespace = interfaceNamespace;
            }
            emitter.setIntfNamespace(targetNamespace);

            emitter.setLocationUrl(locationUrl);
            emitter.setServiceDesc(serviceDesc);
            emitter.setTypeMappingRegistry(msgContext.getTypeMappingRegistry());

            String wsdlPortType = (String) service.getOption(OPTION_WSDL_PORTTYPE);
            String wsdlServiceElement = (String) service.getOption(OPTION_WSDL_SERVICEELEMENT);
            String wsdlServicePort = (String) service.getOption(OPTION_WSDL_SERVICEPORT);
            String wsdlInputSchema = (String) service.getOption(OPTION_WSDL_INPUTSCHEMA);
            String wsdlSoapActinMode = (String) service.getOption(OPTION_WSDL_SOAPACTION_MODE);
            String extraClasses = (String) service.getOption(OPTION_EXTRACLASSES);

            if (wsdlPortType != null && wsdlPortType.length() > 0) {
                emitter.setPortTypeName(wsdlPortType);
            }
            if (wsdlServiceElement != null && wsdlServiceElement.length() > 0) {
                emitter.setServiceElementName(wsdlServiceElement);
            }
            if (wsdlServicePort != null && wsdlServicePort.length() > 0) {
                emitter.setServicePortName(wsdlServicePort);
            }
            if (wsdlInputSchema != null && wsdlInputSchema.length() > 0) {
                emitter.setInputSchema(wsdlInputSchema);
            }
            if (wsdlSoapActinMode != null && wsdlSoapActinMode.length() > 0) {
                emitter.setSoapAction(wsdlSoapActinMode);
            }

            if (extraClasses != null && extraClasses.length() > 0) {
                emitter.setExtraClasses(extraClasses);
            }

            if (msgContext.isPropertyTrue(AxisEngine.PROP_EMIT_ALL_TYPES)) {
                emitter.setEmitAllTypes(true);
            }

            Document doc = emitter.emit(Emitter.MODE_ALL);

            msgContext.setProperty("WSDL", doc);
        } catch (NoClassDefFoundError e) {
            entLog.info(Messages.getMessage("toAxisFault00"), e);
            throw new AxisFault(e.toString(), e);
        } catch (Exception e) {
            entLog.info(Messages.getMessage("toAxisFault00"), e);
            throw AxisFault.makeFault(e);
        }

        if (log.isDebugEnabled())
            log.debug("Exit: BasicProvider::generateWSDL (" + this +")");
    }

由于RPCProvider添加至handler链中,故也需完成generateWSDL任务。该任务由父类
BasicProvider完成。实际生成WSDL的任务委托至Emitter类处理

至此,整个服务部署以及WSDL描述算是梳理完毕。

你可能感兴趣的:(apache,Web,servlet,浏览器,IE)