Chapter 13: Host and Engine

Overview

Two topics of discussion in this chapter are hosts and engines. You use a host if you want to run more than one context in the same Tomcat deployment. In theory, you do not need a host if you only have one context, as stated in the description of the org.apache.catalina.Context interface:

本章讨论的两个主题是主机和引擎。如果您想在同一个Tomcat部署中运行多个上下文,则可以使用主机。理论上,如果只有一个上下文,则不需要主机,如org.apache.catalina.Context接口的描述所述:

The parent Container attached to a Context is generally a Host, but may be some other implementation, or may be omitted if it is not necessary.

与上下文相关联的父容器通常是主机,但也可以是其他实现,或者如果不需要则可以省略。

In practice, however, a Tomcat deployment always needs a host. Why this is so is explained in the section, "Why You Cannot Live without a Host" later in this chapter.

然而,在实践中,Tomcat部署始终需要一个主机。为什么这样是解释在本章后面的“为什么您不能没有主机”的部分。

An engine represents the entire Catalina servlet engine. If used, an engine is always the top level container. Child containers added to an engine are normally implementations of org.apache.catalina.Host or org.apache.catalina.Context. An engine is used in a Tomcat deployment by default. In this deployment, the engine has one host, the default host.

引擎代表整个Catalina servlet引擎。

如果使用引擎,则引擎始终是顶级容器。

添加到引擎的子容器通常是org.apache.catalina.Hostorg.apache.catalina.Context的实现。

在Tomcat部署中,默认使用引擎。

在此部署中,引擎有一个主机,即默认主机。

This chapter discusses classes related to the Host and Engine interfaces. It starts with the Host interface followed by the StandardHost, StandardHostMapper (in Tomcat 4) and StandardHostValve classes. Next, to conclude the discussion of Host, an application is presented that demonstrates the use of a host as a top level container. The Engine interface begins the second topic of discussion, followed by the StandardEngine and the StandardEngineValve classes. Then, comes the second application in this chapter, which illustrates the use of an engine as the top level container.

本章讨论与主机和引擎接口相关的类。

首先介绍主机接口,然后是 StandardHostStandardHostMapper(在Tomcat 4中)和 StandardHostValve 类。

接下来,为了总结对主机的讨论,介绍一个应用程序,演示了将主机用作顶级容器的用法。

引擎接口开始第二个讨论主题,然后是StandardEngineStandardEngineValve类。

然后,本章中的第二个应用程序展示了将引擎用作顶级容器的用法。

The Host Interface 主机接口

A host is represented by the org.apache.catalina.Host interface. This interface extends the Container interface and is given in Listing 13.1.

主机由org.apache.catalina.Host接口表示。此接口扩展了Container接口,如清单13.1所示。

Listing 13.1: The Host interface

清单13.1:主机接口

package org.apache.catalina;
public interface Host extends Container {
 public static final String ADD_ALIAS_EVENT = "addAlias";
 public static final String REMOVE_ALIAS_EVENT = "removeAlias";
 /**
 * Return the application root for this Host.
 * This can be an absolute
 * pathname, a relative pathname, or a URL.
 */
 public String getAppBase();
 /**
 * Set the application root for this Host. This can be an absolute
 * pathname, a relative pathname, or a URL.
 *
 * @param appBase The new application root
 */
 public void setAppBase(String appBase);
 /**
 * Return the value of the auto deploy flag.
 * If true, it indicates that
 * this host's child webapps should be discovred and automatically
 * deployed.
 */
 public boolean getAutoDeploy();
 /**
 * Set the auto deploy flag value for this host.
 *
 * @param autoDeploy The new auto deploy flag
 */
 public void setAutoDeploy(boolean autoDeploy);
 /**
 * Set the DefaultContext
 * for new web applications.
 *
 * @param defaultContext The new DefaultContext
 */
 public void addDefaultContext(DefaultContext defaultContext);
 /**
 * Retrieve the DefaultContext for new web applications.
 */
 public DefaultContext getDefaultContext();
 /**
 * Return the canonical, fully qualified, name of the virtual host
 * this Container represents.
 */
 public String getName();
 /**
 * Set the canonical, fully qualified, name of the virtual host
 * this Container represents.
 *
 * @param name Virtual host name
 *
 * @exception IllegalArgumentException if name is null
 */
 public void setName(String name);
 /**
 * Import the DefaultContext config into a web application context.
 *
 * @param context web application context to import default context
 */
 public void importDefaultContext(Context context);
 /**
 * Add an alias name that should be mapped to this same Host.
 *
 * @param alias The alias to be added
 */
 public void addAlias(String alias);
 /**
 * Return the set of alias names for this Host. If none are defined,
 * a zero length array is returned.
 */
 public String[] findAliases();
 /**
 * Return the Context that would be used to process the specified
 * host-relative request URI, if any; otherwise return
 * <code>null</code>.
 *
 * @param uri Request URI to be mapped
 */
 public Context map(String uri);
 /**
 * Remove the specified alias name from the aliases for this Host.
 * @param alias Alias name to be removed
 */
 public void removeAlias(String alias);
}

Of particular importance is the map method that returns the right context to handle the incoming request. The implementation of this method can be found in the StandardHost class, discussed in the next section.

尤其重要的是 map 方法,它可以返回正确的上下文以处理传入的请求。

该方法的实现可以在 StandardHost 类中找到,将在下一节讨论。

StandardHost

The org.apache.catalina.core.StandardHost class is the standard implementation of Host. This class extends the org.apache.catalina.core.ContainerBase class and implements the Host and Deployer interfaces. Deployer is discussed in Chapter 17.

org.apache.catalina.core.StandardHost类是Host的标准实现。

该类继承自org.apache.catalina.core.ContainerBase类,并实现了HostDeployer接口。

Deployer 接口在第17章中进行了讨论。

Just like the StandardContext and the StandardWrapper classes, the StandardHost class's constructor adds the basic valve to its pipeline:

就像 StandardContextStandardWrapper 类一样,StandardHost类的构造函数将基本阀门添加到其管道中:

public StandardHost() {
 super();
 pipeline.setBasic(new StandardHostValve());
}

As you can see, the basic valve is an instance of org.apache.catalina.core.StandardHostValve.

正如你所看到的,基本阀门是 org.apache.catalina.core.StandardHostValve 的一个实例。

When started, i.e. when its start method is called, the StandardHost adds two valves: ErrorReportValve and ErrorDispatcherValve. Both valves are part of the org.apache.catalina.valves package. The start method of StandardHost in Tomcat 4 is given in Listing 13.2:

当启动时,也就是调用它的start方法时,StandardHost 会添加两个阀门:ErrorReportValveErrorDispatcherValve

这两个阀门都属于org.apache.catalina.valves包。Tomcat 4中StandardHoststart方法如下(见清单13.2):

Listing 13.2: The start method of StandardHost

清单13.2:StandardHoststart 方法

public synchronized void start() throws LifecycleException {  
    // Set error report valve  
    if ((errorReportValveClass != null)  
            && (!errorReportValveClass.equals(""))) {  
        try {  
            Valve valve =  
                    (Valve) Class.forName(errorReportValveClass).newInstance();  
            addValve(valve);  
        }  
        catch (Throwable t) {  
            log(sm.getString  
                    ("StandardHost.invalidErrorReportValveClass",  
                            errorReportValveClass));  
        }  
    }  
    // Set dispatcher valve  
    addValve(new ErrorDispatcherValve());  
    super.start();  
}

Note In Tomcat 5, the start method is similar, except for the fact that it includes code for constructing JXM object name, which will only be discussed in Chapter 20.

注意 在 Tomcat 5 中,启动方法与此类似,只是其中包含了用于构造 JXM 对象名的代码,这一点将在第 20 章中讨论。

The value of errorReportValveClass is determined in the StandardHost class as follows:

错误报告阀类(errorReportValveClass)的值在 StandardHost 类中确定如下:

private String errorReportValveClass =
 "org.apache.catalina.valves.ErrorReportValve";

For every incoming request, the invoke method of the host will be called. Since StandardHost does not have its own implementation of the invoke method, the invoke method of ContainerBase, its parent class, will be called. The invoke method in turn calls the invoke method of the StandardHostValve, the basic valve of StandardHost. The invoke method of the StandardHostValve is discussed in the section "StandardHostValve" below. Among others, the StandardHostValve class's invoke method calls the StandardHost class's map method to obtain the right context to handle the request. The implementation of the map method in StandardHost is given in Listing 13.3.

对于每个传入的请求,将调用主机的invoke方法。

由于StandardHost没有自己的invoke方法实现,因此将调用其父类ContainerBaseinvoke方法。

而invoke方法又会调用StandardHost的基本阀门 StandardHostValveinvoke 方法。

StandardHostValveinvoke 方法将在下面的" StandardHostValve "部分进行讨论。

其中,StandardHostValve 类的 invoke 方法调用 StandardHost 类的 map 方法来获取处理请求的正确上下文。

StandardHostmap 方法的实现如清单13.3所示。

Listing 13.3: The map method in the StandardHost class

第13.3节:StandardHost 类中的map方法

 public Context map(String uri) {
        if (debug > 0)
            log("Mapping request URI '" + uri + "'");
        if (uri == null)
            return (null);
        // Match on the longest possible context path prefix
        if (debug > 1)
            log(" Trying the longest context path prefix");
        Context context = null;
        String mapuri = uri;
        while (true) {
            context = (Context) findChild(mapuri);
            if (context != null)
                break;
            int slash = mapuri.lastIndexOf('/');
            if (slash < 0)
                break;
            mapuri = mapuri.substring(0, slash);
        }
        // If no Context matches, select the default Context
        if (context == null) {
            if (debug > 1)
                log(" Trying the default context");
            context = (Context) findChild("");
        }
        // Complain if no Context has been selected
        if (context == null) {
            log(sm.getString("standardHost.mappingError", uri));
            return (null);
        }
        // Return the mapped Context (if any)
        if (debug > 0)
            log(" Mapped to context '" + context.getPath() + "'");
        return (context);
    }

Note that the ContainerBase class in Tomcat 4 also defines a map method with the following signature:

请注意,Tomcat 4 中的 ContainerBase 类也定义了一个具有以下签名的 map 方法:

public Container map(Request request, boolean update);

In Tomcat 4 the invoke method in StandardHostValve calls the map method in ContainerBase, which in turn calls the map method in StandardHost. Tomcat 5 does not use a mapper component, and the right context is obtained from the request object.

在Tomcat 4中,StandardHostValve 中的 invoke 方法调用 ContainerBase 中的 map 方法,而 ContainerBase 又调用StandardHost中的map方法。

而在Tomcat 5中,不再使用映射器组件,而是直接从请求对象中获取正确的上下文。

StandardHostMapper

In Tomcat 4 the ContainerBase class, the parent class of StandardHost, creates a default mapper by calling its addDefaultMapper method from the start method. The type of the default mapper is given by the mapperClass property. Here is the addDefaultMapper method of ContainerBase:

在Tomcat 4中,StandardHost 的父类 ContainerBase 在其 start 方法中通过调用 addDefaultMapper 方法创建了一个默认的映射器。

默认映射器的类型由 mapperClass 属性指定。

以下是 ContainerBaseaddDefaultMapper方法的实现:

  
protected void addDefaultMapper(String mapperClass) {  
    // Do we need a default Mapper?  
    if (mapperClass == null)  
        return;  
    if (mappers.size() >= 1)  
        return;  
    // Instantiate and add a default Mapper  
    try {  
        Class clazz = Class.forName(mapperClass);  
        Mapper mapper = (Mapper) clazz.newInstance();  
        mapper.setProtocol("http");  
        addMapper(mapper);  
    }  
    catch (Exception e) {  
        log(sm.getString("containerBase.addDefaultMapper", mapperClass),  
                e);  
    }  
}

The StandardHost class defines the mapperClass variable as follows:

StandardHost 类对 mapperClass 变量的定义如下:

private String mapperClass =
 "org.apache.catalina.core.StandardHostMapper";

Also, the StandardHost class's start method calls super.start() at the end of its body, thus ensuring the creation of a default mapper.

此外,StandardHost 类的启动方法会在其主体的末尾调用 super.start(),从而确保创建默认映射器。

Note The standardContext class in Tomcat 4 uses a slightly different approach to creating a default mapper. Its start method does not call supoer.start(). Instead, the Standardcontext class's start method calls the addDefaultMapper method passing the mapperClass variable.

注意 Tomcat 4 中的 standardContext 类在创建默认映射器时使用的方法略有不同。它的启动方法不调用 supoer.start()。相反,Standardcontext 类的启动方法会调用 addDefaultMapper 方法,并传递 mapperClass 变量。

The most important method in StandardHostMapper is, of course, map. Here it is.

StandardHostMapper 中最重要的方法当然是 map。就是这个。

public Container map(Request request, boolean update) {  
    // Has this request already been mapped?  
    if (update && (request.getContext() != null))  
        return (request.getContext());  
    // Perform mapping on our request URI  
    String uri = ((HttpRequest) request).getDecodedRequestURI();  
    Context context = host.map(uri);  
    // Update the request (if requested) and return the selected Context  
    if (update) {  
        request.setContext(context);  
        if (context != null)  
            ((HttpRequest) request).setContextPath(context.getPath());  
        else            ((HttpRequest) request).setContextPath(null);  
    }  
    return (context);  
}

Notice that the map method simply calls the Host's map method!

请注意,map 方法只是调用 Hostmap 方法!

StandardHostValve

The org.apache.catalina.core.StandardHostValve class is the basic valve of StandardHost. Its invoke method (in Listing 13.4) is called when there is an incoming HTTP request.

org.apache.catalina.core.StandardHostValve 类是 StandardHost 的基本阀门。当有 HTTP 请求传入时,会调用它的 invoke 方法(见清单 13.4)。

Listing 13.4: The invoke method of StandardHostValve

清单 13.4: StandardHostValve 的 invoke 方法

public void invoke(Request request, Response response,
                       ValveContext valveContext)
            throws IOException, ServletException {
        // Validate the request and response object types
        if (!(request.getRequest() instanceof HttpServletRequest) ||
                !(response.getResponse() instanceof HttpServletResponse)) {
            return; // NOTE - Not much else we can do generically
        }
        // Select the Context to be used for this Request
        StandardHost host = (StandardHost) getContainer();
        Context context = (Context) host.map(request, true);
        if (context == null) {
            ((HttpServletResponse) response.getResponse()).sendError
                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            sm.getstring("StandardHost.noContext"));
            return;
        }
        // Bind the context CL to the current thread
        Thread.currentThread().setContextClassLoader
                (context.getLoader().getClassLoader());
        // Update the session last access time for our session (if any)
        HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
        String sessionId = hreq.getRequestedSessionId();
        if (sessionId != null) {
            Manager manager = context.getManager();
            if (manager != null) {
                Session session = manager.findSession(sessionId);
                if ((session != null) && session.isValid())
                    session.access();
            }
        }
        // Ask this Context to process this request
        context.invoke(request, response);
    }

The invoke method in Tomcat 4 obtains the appropriate context by calling the map method of StandardHost.

Tomcat 4 中的 invoke 方法通过调用 StandardHost 的 map 方法来获取适当的上下文。

// Select the Context to be used for this Request
 StandardHost host = (StandardHost) getContainer();
 Context context = (Context) host.map(request, true);

Note There is a round trip when obtaining the Context object above. The map method above accepts two arguments. This is the map method defined in the ContainerBase class. The map method in the ContainerBase class then finds the appropriate mapper in the child object (i.e. the StandardHost instance in this case) and calls its map method.

注意:在获取上述的Context对象时存在一个往返操作。上面的map方法接受两个参数。这是在ContainerBase类中定义的map方法。ContainerBase类中的map方法然后在子对象(在这种情况下是StandardHost实例)中找到适当的映射器,并调用其map方法。

The invoke method then obtains the session object associated with the request object and calls its access method. The access method updates the last access time. Here is the access method in the org.apache.catalina.session.StandardSession class:

然后,invoke方法获取与请求对象关联的会话对象,并调用其access方法。

access方法更新最后访问时间。以下是org.apache.catalina.session.StandardSession类中的access方法:

public void access() {
 this.isNew = false;
 this.lastAccessedTime = this.thisAccessedTime;
 this.thisAccessedTime = System.currentTimeMillis();
}

Finally, the invoke method calls the invoke method of the context, letting the context handle the request.

最后,invoke 方法会调用上下文的 invoke 方法,让上下文处理请求。

Why You Cannot Live without a Host

A Tomcat deployment (Tomcat 4 and 5) must have a host if each context is to be configured using ContextConfig. The reason is this.

如果要使用 ContextConfig 配置每个上下文,Tomcat 部署(Tomcat 4 和 5)必须有一个主机。原因是这样的。

ContextConfig needs the location of the application web.xml file. It attempts to open the web.xml file in its applicationConfig method. Here is the fragment of the applicationConfig method:

ContextConfig 需要应用程序 web.xml 文件的位置。

它会尝试在其 applicationConfig 方法中打开 web.xml 文件。下面是 applicationConfig 方法的片段:

synchronized (webDigester) {
 try {
 URL url =
 servletContext.getResource(Constants.ApplicationWebXml);
 InputSource is = new InputSource(url.toExternalForm());
 is.setByteStream(stream);
 ...
 webDigester.parse(is);
 ...

where Constants.ApplicationWebXml is /WEB-INF/web.xml, the relative path to the web.xml file, and servletContext is an object of type org.apache.catalina.core.ApplicationContext (implements javax.servlet.ServletContext).

Constants.ApplicationWebXml为/WEB-INF/web.xml,是web.xml文件的相对路径,servletContext是类型为org.apache.catalina.core.ApplicationContext(实现javax.servlet.ServletContext接口)的对象。

Here is the getResource method of ApplicationContext:

下面是ApplicationContext的getResource方法:

public URL getResource(String path)
 throws MalformedURLException {
 DirContext resources = context.getResources();
 if (resources != null) {
 String fullPath = context.getName() + path;
 // this is the problem. Host must not be null
 String hostName = context.getParent().getName();

The last line shows clearly that a context must have a parent (a host) if it is to be configured by a ContextConfig. You will learn how the web.xml file is parsed in Chapter 15, "Digester". In short, you must have a host unless you write your own ContextConfig class.

最后一行明确显示,如果要通过ContextConfig进行配置,则上下文必须有一个父级(主机)。

您将在第15章“Digester”中学习如何解析web.xml文件。简而言之,除非编写自己的ContextConfig类,否则必须有一个主机。

Application 1

The first application in this chapter demonstrates the use of a host as the top level container. This application uses two classes, ex13.pyrmont.core.SimpleContextConfig and ex13.pyrmont.startup.Bootstrap1 class. The SimpleContextConfig class is copied from Chapter 11 and the Bootstrap2 class is given in Listing 13.5:

本章中的第一个应用程序演示了将主机作为顶级容器的用法。该应用程序使用了两个类,ex13.pyrmont.core.SimpleContextConfig和ex13.pyrmont.startup.Bootstrap1类。

SimpleContextConfig类是从第11章复制而来,Bootstrap1类在第13.5节中给出:

Listing 13.5: The Bootstrap1 Class

第13.5节:Bootstrap1类


    package ex13.pyrmont.startup;
import ex13.pyrmont.core.SimpleContextConfig;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Loader;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.loader.WebappLoader;
    public final class Bootstrap1 {
        public static void main(String[] args) {
            System.setProperty("catalina.base",
                    System.getProperty("user.dir"));
            Connector connector = new HttpConnector();
            Wrapper wrapper1 = new StandardWrapper();
            wrapper1.setName("Primitive");
            wrapper1.setServletClass("PrimitiveServlet");
            Wrapper wrapper2 = new StandardWrapper();
            wrapper2.setName("Modern");
            wrapper2.setServletClass("ModernServlet");
            Context context = new StandardContext();
            // StandardContext's start method adds a default mapper
            context.setPath("/app1");
            context.setDocBase("app1");
            context.addChild(wrapper1);
            context.addChild(wrapper2);
            LifecycleListener listener = new SimpleContextConfig();
            ((Lifecycle) context).addLifecycleListener(listener);
            Host host = new StandardHost();
            host.addChild(context);
            host.setName("localhost");
            host.setAppBase("webapps");
            Loader loader = new WebappLoader();
            context.setLoader(loader);
            // context.addServletMapping(pattern, name);
            context.addServletMapping("/Primitive", "Primitive");
            context.addServletMapping("/Modern", "Modern");
            connector.setContainer(host);
            try {
                connector.initialize();
                ((Lifecycle) connector).start();
                ((Lifecycle) host).start();
                // make the application wait until we press a key.
                System.in.read();
                ((Lifecycle) host).stop();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Running the Applications

To run the application in Windows, from the working directory, type the following:

要在 Windows 中运行应用程序,请在工作目录中键入以下内容:

java -classpath ./lib/servlet.jar;./lib/commonscollections.jar;./lib/commons—digester.jar;./ ex13.pyrmont.startup.Bootstrap1 In Linux, you use a colon to separate two libraries.
java -classpath ./lib/servlet.jar:./lib/commonscollections.jar:./lib/commons-digester.jar:./ ex13.pyrmont.startup.Bootstrap1

To invoke PrimitiveServlet, use the following URL in your browser.

要调用 PrimitiveServlet,请在浏览器中使用以下 URL。

http://localhost:8080/app1/Primitive

To invoke ModernServlet, use the following URL.

要调用 ModernServlet,请使用以下 URL。

http://localhost:8080/app1/Modern

The Engine Interface

The org.apache.catalina.Engine interface represents an engine. An engine represents the entire Catalina servlet engine. You would want to use an engine if you want to support multiple virtual hosts. In fact, a Tomcat deployment normally uses an engine.

org.apache.catalina.Engine 接口表示一个引擎。一个引擎代表整个 Catalina servlet 引擎。如果要支持多个虚拟主机,就需要使用引擎。事实上,Tomcat 部署通常会使用一个引擎。

The Engine interface is shown in Listing 13.6:

引擎接口如清单 13.6 所示:

Listing 13.6: The Engine Interface

清单 13.6: 引擎接口


package org.apache.catalina;
    public interface Engine extends Container {
        /**
         * Return the default hostname for this Engine.
         */
        public String getDefaultHost();
        /**
         * Set the default hostname for this Engine.
         *
         * @param defaultHost The new default host
         */
        public void setDefaultHost(String defaultHost);
        /**
         * Retrieve the JvmRouteId for this engine.
         */
        public String getJvmRoute();
        /**
         * Set the JvmRouteId for this engine.
         *
         * @param jvmRouteId the (new) JVM Route ID. Each Engine within a
         * cluster must have a unique JVM Route ID.
         */
        public void setJvmRoute(String jvmRouteId);
        /**
         * Return the <code>Service</code> with which we are associated (if
         * any).
         */
        public Service getService();
        /**
         * Set the <code>Service</code> with which we are associated (if
         * any).
         *
         * @param service The service that owns this Engine
         */
        public void setService(Service service);
        /**
         * Set the DefaultContext
         * for new web applications.
         *
         * @param defaultContext The new DefaultContext
         */
        public void addDefaultContext(DefaultContext defaultContext);
        /**
         * Retrieve the DefaultContext for new web applications.
         */
        public DefaultContext getDefaultContext();
        /**
         * Import the DefaultContext config into a web application context.
         *
         * @param context web application context to import default context
         */
        public void importDefaultContext(Context context);
    }

You can set a default host or add a default context to an Engine. Note also that an engine can be associated with a service. Services are discussed in Chapter 14.

可以为引擎设置默认主机或添加默认上下文。

还请注意,引擎可以与服务关联。第 14 章将讨论服务。

StandardEngine

The org.apache.catalina.core.StandardEngine is the standard implementation of the Engine interface. Compared to StandardContext and StandardHost, the StandardEngine class is relatively small. When instantiated, the StandardEngine class adds a basic valve, as indicated in its constructor:

org.apache.catalina.core.StandardEngine是Engine接口的标准实现。

与StandardContext和StandardHost相比,StandardEngine类相对较小。

当实例化StandardEngine类时,它会根据其构造函数中的指示添加一个基本的阀门:

public StandardEngine() {
 super();
 pipeline.setBasic(new StandardEngineValve());
}

As the top level container, a StandardEngine will have child containers. A child container of a StandardEngine must be a host. An exception will be thrown if you try to add a non-host container. Here is the addChild method of StandardEngine.

作为顶级容器,StandardEngine将拥有子容器。

StandardEngine的子容器必须是一个主机。

如果尝试添加非主机容器,将会抛出异常。以下是StandardEngine的addChild方法。

public void addChild(Container child) {
 if (!(child instanceof Host))
 throw new IllegalArgumentException
 (sm.getString("StandardEngine.notHost"));
 super.addChild(child);
}

As a top level container, it is impossible for an engine to have a parent. An exception will be thrown if you try to set a parent, as displayed by the StandardEngine class's setParent method:

作为顶层容器,引擎不可能有父对象。

正如 StandardEngine 类的 setParent 方法所显示的那样,如果尝试设置父类,就会出现异常:

public void setParent(Container container) {
 throw new IllegalArgumentException
 (sm.getString("standardEngine.notParent"));
}

StandardEngineValve

The org.apache.catalina.core.StandardEngineValve is the basic valve of StandardEngine. The invoke method of StandardEngineValve is presented in Listing 13.7.

org.apache.catalina.core.StandardEngineValveStandardEngine 的基本阀门。

清单 13.7 介绍了 StandardEngineValve 的 invoke 方法。

Listing 13.7: The invoke method of StandardEngineValve

清单 13.7:StandardEngineValve 的调用方法

public void invoke(Request request, Response response,
                       ValveContext valveContext)
            throws IOException, ServletException {
        // Validate the request and response object types
        if (!(request.getRequest() instanceof HttpServletRequest) ||
                !(response.getResponse() instanceof HttpServletResponse)) {
            return; // NOTE - Not much else we can do generically
        }
        // Validate that any HTTP/1.1 request included a host header
        HttpServletRequest hrequest = (HttpServletRequest) request;
        if ("HTTP/1.1".equals(hrequest.getProtocol()) &&
                (hrequest.getServerName() == null)) {
            ((HttpServletResponse) response.getResponse()).sendError
                    (HttpServletResponse.SC_BAD_REQUEST,
                            sm.getString("standardEngine.noHostHeader",
                                    request.getRequest().getServerName()));
            return;
        }
        // Select the Host to be used for this Request
        StandardEngine engine = (StandardEngine) getContainer();
        Host host = (Host) engine.map(request, true);
        if (host == null) {
            ((HttpServletResponse) response.getResponse()).sendError
                    (HttpServletResponse.SC_BAD_REQUEST,
                            sm.getString("standardEngine.noHost",
                                    request.getRequest().getServerName()));
            return;
        }
        // Ask this Host to process this request
        host.invoke(request, response);
    }

After validating the type of the request and response objects, the invoke method obtains the Host instance used for processing the request. It obtains the Host by calling the Engine's map method. Once the Host is obtained, its invoke method is called.

在验证请求和响应对象的类型后,invoke 方法会获取用于处理请求的 Host 实例。

它通过调用引擎的 map 方法获取 Host。获取 Host 后,就会调用其 invoke 方法。

Application 2

The second application in this chapter demonstrates the use of an engine as the top level container. This application uses two classes, ex13.pyrmont.core.SimpleContextConfig and ex13.pyrmont.startup.Bootstrap2 class. The Bootstrap2 class is given in Listing 13.8:

本章的第二个应用程序演示了将引擎作为顶级容器的使用。该应用程序使用了两个类,ex13.pyrmont.core.SimpleContextConfig和ex13.pyrmont.startup.Bootstrap2类。

Bootstrap2类的代码如下(见13.8代码清单):

Listing 13.8: The Bootstrap2 class

清单 13.8: Bootstrap2 类


    package ex13.pyrmont.startup;
//Use engine
import ex13.pyrmont.core.SimpleContextConfig;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Loader;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.loader.WebappLoader;
    public final class Bootstrap2 {
        public static void main(String[] args) {
            System.setProperty("catalina.base",
                    System.getProperty("user.dir"));
            Connector connector = new HttpConnector();
            Wrapper wrapper1 = new StandardWrapper();
            wrapper1.setName("Primitive");
            wrapper1.setServletClass("PrimitiveServlet");
            Wrapper wrapper2 = new StandardWrapper();
            wrapper2.setName("Modern");
            wrapper2.setServletClass("ModernServlet");
            Context context = new StandardContext();
            // StandardContext's start method adds a default mapper
            context.setPath("/app1");
            context.setDocBase("app1");
            context.addChild(wrapper1);
            context.addChild(wrapper2);
            LifecycleListener listener = new SimpleContextConfig();
            ((Lifecycle) context).addLifecycleListener(listener);
            Host host = new StandardHost();
            host.addChild(context);
            host.setName("localhost");
            host.setAppBase("webapps");
            Loader loader = new WebappLoader();
            context.setLoader(loader);
            // context.addServletMapping(pattern, name);
            context.addServletMapping("/Primitive", "Primitive");
            context.addServletMapping("/Modern", "Modern");
            Engine engine = new StandardEngine();
            engine.addChild(host);
            engine.setDefaultHost("localhost");
            connector.setContainer(engine);
            try {
                connector.initialize();
                ((Lifecycle) connector).start();
                ((Lifecycle) engine).start();
                // make the application wait until we press a key.
                System.in.read();
                ((Lifecycle) engine).stop();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Running the Applications

To run the application in Windows, from the working directory, type the following:

在Windows中运行应用程序,从工作目录中输入以下命令:

java -classpath ./lib/servlet.jar;./lib/commons-collections.jar;./lib/commons-digester.jar;./ex13.pyrmont.startup.Bootstrap2

In Linux, you use a colon to separate two libraries.

在Linux中,使用冒号来分隔两个库。

java -classpath ./lib/servlet.jar:./lib/commonscollections.jar:./lib/commons-digester.jar:./ ex13.pyrmont.startup.Bootstrap2

To invoke PrimitiveServlet, use the following URL in your browser.

要调用PrimitiveServlet,在浏览器中使用以下URL。

http://localhost:8080/app1/Primitive

To invoke ModernServlet, use the following URL.

要调用ModernServlet,请使用以下URL。

http://localhost:8080/app1/Modern

Summary

In this chapter you have learned about two types of containers: host and engine. This chapter also explained the classes related to both containers. Two applications are also presented that show the use of a host and an engine as top level containers.

在本章中,您学习了两种类型的容器:主机和引擎。

本章还解释了与这两种容器相关的类。

还介绍了两个应用程序,展示了主机和引擎作为顶级容器的使用方式。


Xander
195 声望50 粉丝