首页 > 其它 > Tomcat 5.5.26 Administration Tool HTTP Status 500 解决前后

Tomcat 5.5.26 Administration Tool HTTP Status 500 解决前后

闲话少说,如果您也在使用 Tomcat 5.5.26 Administration Tool 的 Delete Existing Hosts 功能时遇到如下问题,本文至少能提供一种有效的解决方法(贴上错误信息文本,一是给搜索引擎预备的,二来也帮助您确认一下本文是否对症)。

tomcat-admin-tools-http-500

tomcat-admin-tools-http-500


HTTP Status 500 –

——————————————————————————–

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

java.lang.NullPointerException
    java.lang.String.indexOf(Unknown Source)
    java.lang.String.indexOf(Unknown Source)
    org.apache.struts.taglib.logic.MatchTag.condition(MatchTag.java:158)
    org.apache.struts.taglib.logic.MatchTag.condition(MatchTag.java:100)
    org.apache.struts.taglib.logic.ConditionalTagBase.doStartTag(ConditionalTagBase.java:174)
    admin.host.hosts_jsp._jspService(hosts_jsp.java:178)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1085)
    org.apache.struts.action.RequestProcessor.processForwardConfig(RequestProcessor.java:398)
    org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:241)
    org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
    org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.webapp.admin.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:123)

note The full stack trace of the root cause is available in the Apache Tomcat/5.5.26 logs.

——————————————————————————–

Apache Tomcat/5.5.26
如果您只想解决问题,也就是顺利使用 Delete Exsiting Hosts 功能,那么您只需:

  1. 浏览 http://tomcat.apache.org/download-55.cgi,在 Source Code Distributions 下载源代码压缩包(条件允许的话,最好借助 md5 等方式检查一下文件完整性);
  2. 解压缩下载的源代码压缩包,找到 apache-tomcat-5.5.26-srccontainerwebappsadminWEB-INFclassesorgapachewebappadminhostDeleteHostAction.java 的第 116 行,将 “domain” 两侧的一对双引号删除;
  3. 使用您熟悉的方式,重新编译该文件,获得 DeleteHostAction.class 或者 jar 文件(我编译好的 DeleteHostAction.class 可以在 CSDN 下载频道 获取);
  4. 将编译好的文件部署到服务器上的正确位置,%CATALINA_HOME%serverwebappsadminWEB-INFclassesorgapachewebappadminhostDeleteHostAction.class 或者 %CATALINA_HOME%serverwebappsadminWEB-INFlibcatalina-admin.jar,二者必取其一。我采取的方法是重命名 %CATALINA_HOME%serverwebappsadminWEB-INFlibcatalina-admin.jar 把她屏蔽掉,然后把其内容解压缩到 %CATALINA_HOME%serverwebappsadminWEB-INFclasses,这样就可以直接拿 DeletaHostAction.class 文件去替换掉原来的那个,一是怕还有别的 .class 需要改,二是图省事儿,就没用 jar 的方式。

下面就是本人发现这一解决方法的始末。事先声明,本人一直走 ASP.NET 路线,对 Java 及相关技术知之甚少,如有疏漏还请指正,互相学习共同提高。
从上述调用栈我们可以看出,问题出在 admin.host.hosts_jsp._jspService 这个方法中,在源文件 hosts_jsp.java 的 178 行,好,那就开始寻找源文件。费了一番周折才发现,原来 Administration Tool 的源代码都在 Tomcat 5.5.26 的 src 包里:apache-tomcat-5.5.26-src.tar.gz 或 .zip(http://tomcat.apache.org/download-55.cgi)。压缩包中的具体位置是 apache-tomcat-5.5.26-srccontainerwebappsadminhosthosts.jsp。
这中间还有一个插曲,我估计是出于性能考虑,官方发布的这个 Admin Web Application 是把 JSP 编译好了当 Servlet 使,因为发现 %CATALINA_HOME%serverwebappsadminWEB-INFweb.xml 中有 <servlet-mapping /> 配置,把对 JSP 的请求交给编译好的形如 jspname_jsp.class 的 Servlet 来处理。在找到官方发布的源代码之前,我曾经带着学习的目的反编译了那个 admin.host.hosts_jsp.class(位于 %CATALINA_HOME%serverwebappsadminWEB-INFlibcatalina-admin.jar),其内容真是惨不忍睹啊……
我们还是看看正儿八经的源文件吧,hosts.jsp 中有如下一段:
文件片断:apache-tomcat-5.5.26-srccontainerwebappsadminhosthosts.jsp

  •              <logic:match name=”host”                         value='<%= (String)request.getAttribute(“adminAppHost”) %>’>
  •              <font color=’red’>*</font>              </logic:match>
  •              <logic:notMatch name=”host”                         value='<%= (String)request.getAttribute(“adminAppHost”) %>’>
  •               <label for=”hosts”></label>                        <html:multibox property=”hosts”
  •                                 value=”<%= host.toString() %>” styleId=”hosts”/>               </logic:notMatch>
  • 看到这里我就确信,报异常的就是这个地方:既有 <logic:match /> 和 <logic:nomatch /> 标记(尽管不知道她如何起作用,但语义还是能看出来的),又有两个将某种东西强制转换成 String 的地方(第 78 和 82 行)。
    这段源代码和最早遇到的调用栈告诉我,request.getAttribute(“adminAppHost”) 得到了 null。我就很好奇,到底她当初是怎么 setAttribute(“adminAppHost”, value) 的呢?这次就要从页面入手了。登录 Administration Tool,右键右下角的 frame 查看源文件:
    代码片断:EditService[1]

  • <select id=”labelId” onchange=”IA_jumpMenu(‘self’,this)”> <option selected=”selected” value=””>—–Available Actions—–</option>
  • <option disabled=”true” value=””>————————————-</option> <option value=”/admin/AddConnector.do?select=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Create New Connector</option>
  • <option value=”/admin/DeleteConnector.do?select=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Delete Existing Connectors</option> <option value=””>————————————-</option>
  • <option disabled=”true” value=””>————————————-</option> <option value=”/admin/AddHost.do?select=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Create New Host</option>
  • <option value=”/admin/DeleteHost.do?select=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Delete Existing Hosts</option> <option disabled=”true” value=””>————————————-</option>
  • <option disabled=”true” value=””>————————————-</option> <option value=”/admin/AddValve.do?parent=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Create New Valve</option>
  • <option value=”/admin/DeleteValve.do?parent=Catalina%3Atype%3DService%2CserviceName%3DCatalina”>Delete Existing Valves</option> </select>
  • 只看第 103 行即可,她是说,选择“Delete Existing Hosts”下拉列表项之后,发生了 DeleteHost.do(还带了乱七八糟的参数,%3A:%3D=%2C,),托 %CATALINA_HOME%serverwebappsadminWEB-INFstruts-config.xml 的福,找到了 DeleteHost.do 的责任者:
    文件片断:%CATALINA_HOME%serverwebappsadminWEB-INFstruts-config.xml

  •     <!– Set up Delete Hosts transaction –>     <action    path=”/DeleteHost”
  •                type=”org.apache.webapp.admin.host.DeleteHostAction”                name=”hostsForm”
  •                scope=”request”/>
  • 于是去查看 apache-tomcat-5.5.26-srccontainerwebappsadminWEB-INFclassesorgapachewebappadminhostDeleteHostAction.java 的内容。果不其然,这里有 setAttribute:
    文件片断:apache-tomcat-5.5.26-srccontainerwebappsadminweb-infclassesorgapachewebappadminhostdeletehostaction.java

  •         // Set up a form bean containing the currently selected         // objects to be deleted
  •         HostsForm hostsForm = new HostsForm();         String select = request.getParameter(“select”);
  •         String domain = null;         if (select != null) {
  •             String hosts[] = new String[1];             hosts[0] = select;
  •             hostsForm.setHosts(hosts);                          
  •             try {                 domain = (new ObjectName(select)).getDomain();
  •             } catch (Exception e) {                 throw new ServletException
  •                 (“Error extracting service name from the host to be deleted”, e);             }        
  •         }         String adminHost = null;
  •         // Get the host name the admin app runs on         // this host cannot be deleted from the admin tool
  •         try {             adminHost = Lists.getAdminAppHost(
  •                                   mBServer, “domain” ,request);         } catch (Exception e) {
  •             String message =                 resources.getMessage(locale, “error.hostName.bad”,
  •                                         adminHost);             getServlet().log(message);
  •             response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);             return (null);
  •         }         request.setAttribute(“adminAppHost”, adminHost);        
  •         request.setAttribute(“hostsForm”, hostsForm);
  • 代码截取的比较多,先看第 98 和 105 行,知道这个作用域内有个局部变量叫 domain 就行了。然后看第 111 和 115 行,还有第 125 行。好了,现在问题集中在了 Lists.getAdminAppHost() 上。不出意外(也就是不抛异常)的话,显然 Lists.getAdminAppHost() 的返回值被 request.setAttribute() 设置成了 adminAppHost 这个 attribute 的取值。
    那么我们来看看 Lists 她是怎么说的,找到源文件 apache-tomcat-5.5.26-srccontainerwebappsadminWEB-INFclassesorgapachewebappadminLists.java:
    文件片断:apache-tomcat-5.5.26-srccontainerwebappsadminWEB-INFclassesorgapachewebappadminLists.java

  •     /**      * Return the  <code>Host</code> object name string
  •      * that the admin app belongs to.      *
  •      * @param mbserver MBeanServer from which to retrieve the list      * @param request Http request
  •      *      * @exception Exception if thrown while retrieving the list
  •      */     public static String getAdminAppHost
  •         (MBeanServer mbserver, String domain, HttpServletRequest request)         throws Exception {
  •                  // Get the admin app’s host name
  •         StringBuffer sb = new StringBuffer(domain);         sb.append(“:j2eeType=WebModule,*”);  
  •         ObjectName search = new ObjectName(sb.toString());         Iterator names = mbserver.queryNames(search, null).iterator();
  •         String contextPath = request.getContextPath();         String host = null;
  •         String name = null;         ObjectName oname = null;
  •         while (names.hasNext()) {                    name = names.next().toString();
  •             oname = new ObjectName(name);             host = oname.getKeyProperty(“name”);
  •             host = host.substring(2);             int i = host.indexOf(“/”);
  •             if (contextPath.equals(host.substring(i))) {                 host = host.substring(0,i);
  •                 return host;             }
  •         }         return host;
        }
  • 简单来说,getAdminAppHost() 这个方法的第二个参数 domain 被用来寻找 names,而 names 中有我们需要的 host 的内容。经过调试,发现当 domain 取值为 “domain” 时,names.hasNext() 返回 false,host 即最终的返回值亦无可避免成为 null,直至导致 hosts.jsp 中 request.getAttribute(“adminAppHost”) 时得到 null。回过头来看看 DeleteHostAction.java 的第 115 和 116 行吧,第二个参数是常量字符串 “domain” 而不是局部变量 domain,当去掉这一对双引号,再重新编译后,问题看起来就解决了(见下图,逻辑很正确,Admin Tool 所在的 Host 不能删除)。

    现在唯一还困扰我的就是,官方发布的版本为什么会存在这个问题?我相信除了遇到相同问题的我们,有更多的人没有遇到这一问题,尤其是在发现 %CATALINA_HOME%serverwebappsadminWEB-INFweb.xml 中的这句话之后,我被彻底打败了……
    文件片断:%CATALINA_HOME%serverwebappsadminWEB-INFweb.xml

  •     <init-param>       <param-name>domain</param-name>
  •       <param-value>Catalina</param-value>     </init-param>
    1. 还没有评论
    评论提交中, 请稍候...

    留言

    可以使用的标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
    Trackbacks & Pingbacks ( 0 )
    1. 还没有 trackbacks