Chapter 19: Manager Servlet
注意:由於Tomcat 4中的Manager應用程序比Tomcat 5中的稍微簡單一些,它是一個更好的學習工具,因此在本章中進行了討論。
閲讀本章後,您應該也能理解Tomcat 5中的Manager應用程序的工作原理。
以下是Tomcat 4中部署描述符中的Servlet元素。
Overview(概述)
Tomcat 4 and 5 come with the Manager application that you can use to manage deployed applications. Unlike other applications, Manager does not reside in the default deployment directory %CATALINA_HOME%/webapps but in %CATALINA_HOME%/server/webapps. Manager is installed when Tomcat starts because Manager has a descriptor, the manager.xml file, in the %CATALINA_HOME$/webapps directory in Tomcat 4 and the %CATALINA_HOME%/server/webapps directory in Tomcat 5.
Tomcat 4和5都附帶了Manager應用程序,您可以使用它來管理已部署的應用程序。與其他應用程序不同,Manager不駐留在默認的部署目錄%CATALINA_HOME%/webapps中,而是位於%CATALINA_HOME%/server/webapps中。當Tomcat啓動時,會安裝Manager,因為Manager在Tomcat 4中的%CATALINA_HOME$/webapps目錄和Tomcat 5中的%CATALINA_HOME%/server/webapps目錄中都有一個描述符,即manager.xml文件。
Note Context descriptors were discussed in Chapter 18.
注意:上下文描述符在第18章中已經討論過。
This chapter describes the Manager application. It starts by outlining how to use this application to give you the feel of how Manager works. It then explains the ContainerServlet interface.
本章介紹了Manager應用程序。首先概述瞭如何使用該應用程序,以便讓您瞭解Manager的工作方式。然後解釋了ContainerServlet接口。
Using the Manager Application(使用Manager應用程序)
The Manager application can be found in the %CATALINA_HOME%/server/webapps/manager directory for both Tomcat 4 and 5. The main servlet in this application is ManagerServlet. In Tomcat 4 this class belongs to the org.apache.catalina.servlets package, which is one of the packages in Catalina. In Tomcat 5 this class is part of the org.apache.catalina.manager package and is deployed as a JAR file in the WEB-INF/lib directory.
Manager應用程序可以在Tomcat 4和5的%CATALINA_HOME%/server/webapps/manager目錄中找到。該應用程序的主要Servlet是ManagerServlet。
在Tomcat 4中,該類屬於org.apache.catalina.servlets包,該包是Catalina中的一個包。
在Tomcat 5中,該類屬於org.apache.catalina.manager包,並且作為一個JAR文件部署在WEB-INF/lib目錄中。
Note Because the Manager application in Tomcat 4 is slightly simpler than that in Tomcat 5, it is a better learning tool and is therefore discussed in this chapter. You should be able to understand how the Manager application in Tomcat 5 works too, after reading this chapter.
注意 因為 Tomcat 4 中的管理器應用程序比 Tomcat 5 中的稍簡單,它是一個更好的學習工具,因此在本章中討論。
讀完本章後,你應該也能理解 Tomcat 5 中的管理器應用程序是如何工作的。
Here are the servlet elements in the deployment descriptor in Tomcat 4.
以下是 Tomcat 4 部署描述符中的 servlet 元素。
<servlet>
<servlet-name>Manager</servlet-name>
<servlet-class>
org.apache.catalina.servlets.ManagerServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>HTMLManager</servlet-name>
<servlet-class>
org.apache,catalina.servlets.HTMLManagerServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
</servlet>
The first servlet is org.apache.catalina.servlets.ManagerServlet and the second org.apache.catalina.servlets.HTMLManagerServlet. This chapter focuses on the ManagerServlet class.
第一個 servlet 是 org.apache.catalina.servlets.ManagerServlet,第二個是 org.apache.catalina.servlets.HTMLManagerServlet。本章將重點討論 ManagerServlet 類。
The descriptor for this application, manager.xml, tells that the context path for this application is /manager.
此應用程序的描述符 manager.xml 顯示此應用程序的上下文路徑為 /manager。
<Context path="/manager" docBase="../server/webapps/manager"
debug="0" privileged="true">
<!-- Link to the user database we will get roles from -->
<ResourceLink name="users" global="UserDatabase"
type="org.apache.catalina.UserDatabase"/>
</Context>
The first servlet-mapping element tells you how to invoke ManagerServlet.
第一個 servlet 映射元素告訴你如何調用 ManagerServlet。
<servlet-mapping>
<servlet-name>Manager</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
In other words, a URL beginning with the following pattern invokes ManagerServlet:\
換句話説,以下列模式開頭的 URL 會調用 ManagerServlet:\
http://localhost:8080/manager/
However, note that there is also this security-constraint element in the deployment descriptor
不過,請注意部署描述符中還有這樣一個安全約束元素
<security-constraint>
<web-resource-collection>
<web-resource-name>Entire Application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- NOTE: This role is not present in the default users file -—>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
This means, the entire application is restricted to users belonging to the manager role. The auth-login element states that a user can be allowed access to the restricted contents if he/she can supply the correct user name and password using the BASIC authentication.
這意味着,整個應用程序僅限於屬於管理者角色的用户使用。
auth-login 元素規定,如果用户能使用 BASIC 身份驗證提供正確的用户名和密碼,就可以訪問受限內容。
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Tomcat Manager Application</realm-name>
</login-config>
This means, the entire application is restricted to users belonging to the manager role. The auth-login element states that a user can be allowed access to the restricted contents if he/she can supply the correct user name and password using the BASIC authentication.
這意味着,整個應用程序僅限於屬於管理者角色的用户使用。
auth-login 元素規定,如果用户能使用 BASIC 身份驗證提供正確的用户名和密碼,就可以訪問受限內容。
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Tomcat Manager Application</realm-name>
</login-config>
In Tomcat, roles and users are listed in the tomcat-users.xml file in the %CATALINA_HOME%/conf directory. Therefore, to access the Manager application, you must add a manager role with a user belonging to that role. Here is an example:
在 Tomcat 中,角色和用户列在 %CATALINA_HOME%/conf 目錄下的 tomcat-users.xml 文件中。
因此,要訪問管理器應用程序,必須添加一個管理器角色和屬於該角色的用户。
下面是一個示例:
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
<role rolename="manager"/>
<user username="tomcat" password="tomcat" roles="manager "/>
</tomcat-users>
With this tomcat-users.xml file, you can access the Manager application using the user name tomcat and password tomcat.
通過該 tomcat-users.xml 文件,可以使用用户名 tomcat 和密碼 tomcat 訪問 Manager 應用程序。
The following functions are available in the ManagerServlet.
ManagerServlet 提供以下功能。
- list
- start
- stop
- reload
- remove
- resources
- roles
- sessions
- undeploy
- 列表
- 啓動
- 停止
- 重新加載
- 刪除
- 資源
- 角色
- 會話
- 撤消部署
Check the servlet's doGet method to see how you can invoke a function.
查看 servlet 的 doGet 方法,瞭解如何調用函數。
The ContainerServlet Interface
A servlet that implements the org.apache.catalina.ContainerServlet interface will have access to the StandardWrapper object that represents it. Having access to the wrapper, it can also access the context object representing the web application, the deployer (StandardHost instance) in which the context resides, and other objects.
實現 org.apache.catalina.ContainerServlet 接口的 servlet 可以訪問代表它的 StandardWrapper 對象。有了對包裝器的訪問權限,它還可以訪問代表網絡應用程序的上下文對象、上下文所在的部署器(StandardHost 實例)以及其他對象。
The ContainerServlet interface is given in Listing 19.1
ContainerServlet 接口見清單 19.1
Listing 19.1: The ContainerServlet Interface
清單 19.1:ContainerServlet 接口
package org.apache.catalina;
public interface ContainerServlet {
public Wrapper getWrapper();
public void setWrapper(Wrapper wrapper);
}
Catalina invokes the setWrapper method of a servlet implementing ContainerServlet to pass the reference to the StandardWrapper representing that servlet.
Catalina 調用實現 ContainerServlet 的 servlet 的 setWrapper 方法來傳遞對代表該 servlet 的 StandardWrapper 的引用。
Initializing ManagerServlet
As always, a servlet is represented by an org.apache.catalina.core.StandardWrapper instance. The first time the servlet is invoked, the StandardWrapper object's loadServlet is called, which in turns calls the servlet's init method. (See Chapter 11.) In the case of ManagerServlet, you should look at a fragment in the loadServlet method:
與往常一樣,Servlet 由 org.apache.catalina.core.StandardWrapper 實例表示。
首次調用 servlet 時,會調用 StandardWrapper 對象的 loadServlet,然後再調用 servlet 的 init 方法。(請參見第 11 章。)
在 ManagerServlet 的情況下,您應該查看 loadServlet 方法中的一個片段:
...
// Special handling for ContainerServlet instances
if ((servlet instanceof ContainerServlet) &&
isContainerProvidedServlet(actualClass)) {
((ContainerServlet) servlet).setWrapper(this);
}
// Call the initialization method of this servlet
try {
instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
servlet);
servlet.init(facade);
...
where servlet represents the servlet to be loaded (in this case, ManagerServlet).
其中 servlet 表示要加載的 servlet(本例中為 ManagerServlet)。
The if statement in the code fragment above says that if servlet is an instance of org.apache.catalina.ContainerServlet and the isContainerProvidedServlet method returns true, call the ContainerServlet interface's setWrapper method.
上面代碼片段中的 if 語句表示,如果 servlet 是 org.apache.catalina.ContainerServlet 的實例,且 isContainerProvidedServlet 方法返回 true,則調用 ContainerServlet 接口的 setWrapper 方法。
The ManagerServlet class implements ContainerServlet, therefore servlet is an instance of ContainerServlet. The isContainerProvidedServlet method in StandardWrapper is given in Listing 19.2
ManagerServlet 類實現了 ContainerServlet,因此 servlet 是 ContainerServlet 的實例。
清單 19.2 給出了 StandardWrapper 中的 isContainerProvidedServlet 方法
Listing 19.2: The isContainerProvidedServlet method in the StandardWrapper class
清單 19.2:StandardWrapper 類中的 isContainerProvidedServlet 方法
private boolean isContainerProvidedServlet(String classname) {
if (classname.startsWith("org.apache.catalina.")) {
return (true);
}
try {
Class clazz =
this.getClass().getClassLoader().loadClass(classname);
return (ContainerServlet.class.isAssignableFrom(clazz));
}
catch (Throwable t) {
return (false);
}
}
The classname argument passed to isContainerProvidedServlet is the fully-qualified name of the ManagerServlet, which is org.apache.catalina.servlets.ManagerServlet. As such, the isContainerProvidedServlet method returns true.
傳遞給 isContainerProvidedServlet 的 classname 參數是 ManagerServlet 的全稱,即 org.apache.catalina.servlets.ManagerServlet。
因此,isContainerProvidedServlet 方法返回 true。
This method also returns true if the servlet class inidicated by classname is a subtype of ContainerServlet, i.e. if classname is an interface that extends ContainerServlet or a class that implements ContainerServlet.
如果 classname 所指示的 servlet 類是 ContainerServlet 的子類型,即 classname 是擴展 ContainerServlet 的接口或實現 ContainerServlet 的類,則此方法也返回 true。
Note The java.lang.Class class's isAssignableFrom(Class clazz) method returns true if the class or interface represented by the current Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified clazz parameter.
注意 如果當前 Class 對象所代表的類或接口與指定的 clazz 參數所代表的類或接口相同,或者是其超類或超接口,則 java.lang.Class 類的 isAssignableFrom(Class clazz) 方法返回 true。
Therefore, the loadServlet method of the StandardWrapper instance representing ManagerServlet will call the ManagerServlet's setWrapper method. Here is the implementation of the setWrapper method in ManagerServlet.
因此,代表 ManagerServlet 的 StandardWrapper 實例的 loadServlet 方法將調用 ManagerServlet 的 setWrapper 方法。
下面是 ManagerServlet 中 setWrapper 方法的實現。
public void setWrapper(Wrapper wrapper) {
this.wrapper = wrapper;
if (wrapper == null) {
context = null;
deployer = null;
}
else {
context = (Context) wrapper.getParent();
deployer = (Deployer) context.getParent();
}
}
Since the parameter wrapper is not null, the else block will be executed, which means context is assigned the context object representing the Manager application and deployer the StandardHost instance hosting the context. The deployer is especially important because it is used in several methods in ManagerServlet to perform various functions.
由於參數包裝器不為空,else 塊將被執行,這意味着上下文將被分配給代表 Manager 應用程序的上下文對象,而部署器則是託管上下文的 StandardHost 實例。
部署器尤為重要,因為在 ManagerServlet 的多個方法中都會使用它來執行各種功能。
After the setWrapper method of ManagerServlet is called by the StandardWrapper class's loadServlet method, the loadServlet method calls the init method of ManagerServlet.
在 StandardWrapper 類的 loadServlet 方法調用 ManagerServlet 的 setWrapper 方法後,loadServlet 方法會調用 ManagerServlet 的 init 方法。
Listing Deployed Web Applications
You list all deployed web applications by using the following URL:
您可以使用以下 URL 列出所有已部署的網絡應用程序
http://localhost:8080/manager/list
Here is an example of the output:
下面是一個輸出示例:
OK - Listed applications for virtual host localhost
OK - 列出了虛擬主機 localhost 的應用程序
/admin:stopped:0:../server/webapps/admin
/app1:running:0:C:\123data\JavaProjects\Pyrmont\webapps\app1
/manager:running:0:../server/webapps/manager
The URL above invokes the list method of ManagerServlet, which is presented in
Listing 19.3
上面的 URL 調用了 ManagerServlet 的 list 方法,如下所示
清單 19.3
Listing 19.3: The list method of ManagerServlet
清單 19.3:ManagerServlet 的 list 方法
protected void list(PrintWriter writer) {
if (debug >= 1)
log("list: Listing contexts for virtual host '" +
deployer.getName() + "'");
writer.println(sm.getString("managerServlet.listed",
deployer.getName()));
String contextPaths[] = deployer.findDeployedApps();
for (int i = 0; i < contextPaths.length; i++) {
Context context = deployer.findDeployedApp(contextPaths[i]);
String displayPath = contextPaths[i];
if( displayPath.equals("") )
displayPath = "/";
if (context != null ) {
if (context.getAvailable()) {
writer.println(sm.getString("managerServlet.listitem",
displayPath, "running", ""
+ context.getManager().findSessions().length,
context.getDocBase()));
}
else {
writer.println(sm.getString("managerServlet.listitem",
displayPath, "stopped", "0", context.getDocBase()));
}
}
}
}
The list method calls the deployer's findDeployedApps to obtain the paths of all the deployed contexts in Catalina. It then iterates the path array to get each individual context and checks whether or not the context is available. For every context that is available, the list method prints the context path, the string running, the number of user sessions, and the document base. For contexts that are unavailable, the list method prints the context path, the string stopped, 0, and the document base.
list 方法調用部署器的 findDeployedApps 來獲取 Catalina 中所有已部署上下文的路徑。
然後遍歷路徑數組以獲取每個上下文,並檢查該上下文是否可用。
對於每個可用的上下文,list 方法會打印上下文路徑、運行的字符串、用户會話數和文檔庫。
對於不可用的上下文,列表方法會打印上下文路徑、字符串 stopped、0 和文檔庫。
Starting A Web Application
You use the following URL to start a web application:
您可以使用以下 URL 啓動網絡應用程序:
http://localhost:8080/manager/start?path=/contextPath
where contextPath is the context path of the application you want to start. For example, to start the admin application, you use
其中 contextPath 是要啓動的應用程序的上下文路徑。
例如,要啓動管理應用程序,請使用
http://localhost:8080/manager/start?path=/admin
If the application has been started, you'll receive an error notification.
Upon receiving this URL, ManagerServlet invokes the start method, which is presented in Listing 19.4.
如果應用程序已啓動,您將收到錯誤通知。
收到此 URL 後,ManagerServlet 會調用啓動方法,該方法如清單 19.4 所示。
Listing 19.4: The start method of the ManagerServlet class
清單 19.4: ManagerServlet 類的啓動方法
protected void start(PrintWriter writer, String path) {
if (debug >= 1)
log("start: Starting web application at '" + path + "'");
if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
writer.println(sm.getString("managerServlet.invalidPath", path));
return;
}
String displayPath = path;
if( path.equals("/") )
path = "";
try {
Context context = deployer.findDeployedApp(path);
if (context == null) {
writer.println(sm.getString("managerServlet.noContext",
displayPath));
return;
}
deployer.start(path);
if (context.getAvailable())
writer.println
(sm.getString("managerServlet.started", displayPath));
else
writer.println
(sm.getString("managerServlet.startFailed", displayPath));
}
catch (Throwable t) {
getServletContext().log
(sm.getString("managerServlet.startFailed", displayPath), t);
writer.println
(sm.getString("managerServlet.startFailed", displayPath));
writer.println(sm.getString("managerServlet.exception",
t.toString()));
}
}
After some checking, the start method calls the deployer's findDeployedApp method in the try block. This method returns the context object whose path is passed to it. If the context is not null, the start method calls the deployer's start method to start the application.
經過一些檢查後,start 方法會在 try 代碼塊中調用部署器的 findDeployedApp 方法。
該方法會返回傳入路徑的上下文對象。如果上下文對象不為空,start 方法就會調用部署程序的 start 方法來啓動應用程序。
Stopping A Web Application
You use the following URL to stop an application:
您可以使用以下 URL 停止應用程序:
http://localhost:8080/manager/stop?path=/contextPath
where contextPath is the context path of the application you want to stop. If the application is not running, you will get an error message.
其中 contextPath 是要停止的應用程序的上下文路徑。如果應用程序未運行,您將收到一條錯誤消息。
When the ManagerServlet receives the request, it invokes the stop method. The stop method is given in Listing 19.5.
ManagerServlet 收到請求後會調用 stop 方法。停止方法見清單 19.5。
Listing 19.5: The stop method of the ManagerServlet class
清單 19.5:ManagerServlet 類的 stop 方法
protected void stop(PrintWriter writer, String path) {
if (debug >= 1)
log("stop: Stopping web application at '" + path + "'");
if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
writer.println(sm.getString("managerServlet.invalidPath", path));
return;
}
String displayPath = path;
if( path.equals("/") )
path = "";
try {
Context context = deployer.findDeployedApp(path);
if (context == null) {
writer.println(sm.getString("managerServlet.noContext",
displayPath));
return;
}
// It isn't possible for the manager to stop itself
if (context.getPath().equals(this.context.getPath())) {
writer.println(sm.getString("managerServlet.noSelf"));
return;
}
deployer.stop(path);
writer.println(sm.getString("managerServlet.stopped",
displayPath));
}
catch (Throwable t) {
log("ManagerServlet.stop[" + displayPath + "]", t);
writer.println(sm.getString("managerServlet.exception",
t.toString()));
}
}
You should be able to figure out how the stop method works. Other methods in the ManagerServlet class should be easy to digest too.
你應該能夠理解 stop 方法是如何工作的。ManagerServlet 類中的其他方法也應該很容易理解。
Summary
In this chapter you have seen how you can use a special interface, ContainerServlet, to create a servlet with access to the Catalina internal classes. The Manager application that you can use to manage deployed applications has demonstrated how to obtain other objects from the wrapper object. It is very possible to design a servlet with more sophisticated functionality for managing Tomcat
在本章中,你將看到如何使用特殊接口 ContainerServlet 來創建可訪問 Catalina 內部類的 servlet。
您可以用來管理已部署應用程序的管理器應用程序演示瞭如何從封裝對象中獲取其他對象。
您完全可以設計一個具有更復雜功能的 servlet 來管理 Tomcat