Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » manager » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.catalina.manager;
   20   
   21   import java.io.File;
   22   import java.io.IOException;
   23   import java.io.PrintWriter;
   24   import java.io.StringWriter;
   25   import java.text.MessageFormat;
   26   import java.util.Arrays;
   27   import java.util.Collections;
   28   import java.util.Comparator;
   29   import java.util.Date;
   30   import java.util.Iterator;
   31   import java.util.List;
   32   import java.util.Map;
   33   import java.util.TreeMap;
   34   import javax.servlet.ServletException;
   35   import javax.servlet.http.HttpServletRequest;
   36   import javax.servlet.http.HttpServletResponse;
   37   import javax.servlet.http.HttpSession;
   38   
   39   import org.apache.catalina.Container;
   40   import org.apache.catalina.Context;
   41   import org.apache.catalina.Manager;
   42   import org.apache.catalina.Session;
   43   import org.apache.catalina.manager.util.BaseSessionComparator;
   44   import org.apache.catalina.manager.util.ReverseComparator;
   45   import org.apache.catalina.manager.util.SessionUtils;
   46   import org.apache.catalina.util.RequestUtil;
   47   import org.apache.catalina.util.ServerInfo;
   48   import org.apache.catalina.util.URLEncoder;
   49   import org.apache.tomcat.util.http.fileupload.DiskFileUpload;
   50   import org.apache.tomcat.util.http.fileupload.FileItem;
   51   
   52   /**
   53   * Servlet that enables remote management of the web applications deployed
   54   * within the same virtual host as this web application is.  Normally, this
   55   * functionality will be protected by a security constraint in the web
   56   * application deployment descriptor.  However, this requirement can be
   57   * relaxed during testing.
   58   * <p>
   59   * The difference between the <code>ManagerServlet</code> and this
   60   * Servlet is that this Servlet prints out a HTML interface which
   61   * makes it easier to administrate.
   62   * <p>
   63   * However if you use a software that parses the output of
   64   * <code>ManagerServlet</code> you won't be able to upgrade
   65   * to this Servlet since the output are not in the
   66   * same format ar from <code>ManagerServlet</code>
   67   *
   68   * @author Bip Thelin
   69   * @author Malcolm Edgar
   70   * @author Glenn L. Nielsen
   71   * @version $Revision: 918620 $, $Date: 2010-03-03 19:44:19 +0100 (Wed, 03 Mar 2010) $
   72   * @see ManagerServlet
   73   */
   74   
   75   public final class HTMLManagerServlet extends ManagerServlet {
   76   
   77       protected static final URLEncoder URL_ENCODER; 
   78       protected static final String APPLICATION_MESSAGE = "message";
   79       protected static final String APPLICATION_ERROR = "error";
   80       protected String sessionsListJspPath  = "/WEB-INF/jsp/sessionsList.jsp";
   81       protected String sessionDetailJspPath = "/WEB-INF/jsp/sessionDetail.jsp";
   82   
   83       static {
   84           URL_ENCODER = new URLEncoder();
   85           // '/' should not be encoded in context paths
   86           URL_ENCODER.addSafeCharacter('/');
   87       }
   88       // --------------------------------------------------------- Public Methods
   89   
   90       /**
   91        * Process a GET request for the specified resource.
   92        *
   93        * @param request The servlet request we are processing
   94        * @param response The servlet response we are creating
   95        *
   96        * @exception IOException if an input/output error occurs
   97        * @exception ServletException if a servlet-specified error occurs
   98        */
   99       public void doGet(HttpServletRequest request,
  100                         HttpServletResponse response)
  101           throws IOException, ServletException {
  102   
  103           // Identify the request parameters that we need
  104           String command = request.getPathInfo();
  105   
  106           String path = request.getParameter("path");
  107           String deployPath = request.getParameter("deployPath");
  108           String deployConfig = request.getParameter("deployConfig");
  109           String deployWar = request.getParameter("deployWar");
  110   
  111           // Prepare our output writer to generate the response message
  112           response.setContentType("text/html; charset=" + Constants.CHARSET);
  113   
  114           String message = "";
  115           // Process the requested command
  116           if (command == null || command.equals("/")) {
  117           } else if (command.equals("/deploy")) {
  118               message = deployInternal(deployConfig, deployPath, deployWar);
  119           } else if (command.equals("/list")) {
  120           } else if (command.equals("/reload")) {
  121               message = reload(path);
  122           } else if (command.equals("/undeploy")) {
  123               message = undeploy(path);
  124           } else if (command.equals("/expire")) {
  125               message = expireSessions(path, request);
  126           } else if (command.equals("/sessions")) {
  127               try {
  128                   doSessions(path, request, response);
  129                   return;
  130               } catch (Exception e) {
  131                   log("HTMLManagerServlet.sessions[" + path + "]", e);
  132                   message = sm.getString("managerServlet.exception",
  133                           e.toString());
  134               }
  135           } else if (command.equals("/start")) {
  136               message = start(path);
  137           } else if (command.equals("/stop")) {
  138               message = stop(path);
  139           } else if (command.equals("/findleaks")) {
  140               message = findleaks();
  141           } else {
  142               message =
  143                   sm.getString("managerServlet.unknownCommand", command);
  144           }
  145   
  146           list(request, response, message);
  147       }
  148   
  149       /**
  150        * Process a POST request for the specified resource.
  151        *
  152        * @param request The servlet request we are processing
  153        * @param response The servlet response we are creating
  154        *
  155        * @exception IOException if an input/output error occurs
  156        * @exception ServletException if a servlet-specified error occurs
  157        */
  158       public void doPost(HttpServletRequest request,
  159                         HttpServletResponse response)
  160           throws IOException, ServletException {
  161   
  162           // Identify the request parameters that we need
  163           String command = request.getPathInfo();
  164   
  165           if (command == null || !command.equals("/upload")) {
  166               doGet(request,response);
  167               return;
  168           }
  169   
  170           // Prepare our output writer to generate the response message
  171           response.setContentType("text/html; charset=" + Constants.CHARSET);
  172   
  173           String message = "";
  174   
  175           // Create a new file upload handler
  176           DiskFileUpload upload = new DiskFileUpload();
  177   
  178           // Get the tempdir
  179           File tempdir = (File) getServletContext().getAttribute
  180               ("javax.servlet.context.tempdir");
  181           // Set upload parameters
  182           upload.setSizeMax(-1);
  183           upload.setRepositoryPath(tempdir.getCanonicalPath());
  184       
  185           // Parse the request
  186           String basename = null;
  187           String war = null;
  188           FileItem warUpload = null;
  189           try {
  190               List items = upload.parseRequest(request);
  191           
  192               // Process the uploaded fields
  193               Iterator iter = items.iterator();
  194               while (iter.hasNext()) {
  195                   FileItem item = (FileItem) iter.next();
  196           
  197                   if (!item.isFormField()) {
  198                       if (item.getFieldName().equals("deployWar") &&
  199                           warUpload == null) {
  200                           warUpload = item;
  201                       } else {
  202                           item.delete();
  203                       }
  204                   }
  205               }
  206               while (true) {
  207                   if (warUpload == null) {
  208                       message = sm.getString
  209                           ("htmlManagerServlet.deployUploadNoFile");
  210                       break;
  211                   }
  212                   war = warUpload.getName();
  213                   if (!war.toLowerCase().endsWith(".war")) {
  214                       message = sm.getString
  215                           ("htmlManagerServlet.deployUploadNotWar",war);
  216                       break;
  217                   }
  218                   // Get the filename if uploaded name includes a path
  219                   if (war.lastIndexOf('\\') >= 0) {
  220                       war = war.substring(war.lastIndexOf('\\') + 1);
  221                   }
  222                   if (war.lastIndexOf('/') >= 0) {
  223                       war = war.substring(war.lastIndexOf('/') + 1);
  224                   }
  225                   // Identify the appBase of the owning Host of this Context
  226                   // (if any)
  227                   basename = war.substring(0, war.toLowerCase().indexOf(".war"));
  228                   File file = new File(getAppBase(), war);
  229                   if (file.exists()) {
  230                       message = sm.getString
  231                           ("htmlManagerServlet.deployUploadWarExists",war);
  232                       break;
  233                   }
  234                   String path = null;
  235                   if (basename.equals("ROOT")) {
  236                       path = "";
  237                   } else {
  238                       path = "/" + basename.replace('#', '/');
  239                   }
  240   
  241                   if ((host.findChild(path) != null) && !isDeployed(path)) {
  242                       message = sm.getString
  243                           ("htmlManagerServlet.deployUploadInServerXml", war);
  244                       break;
  245                   }
  246   
  247                   if (!isServiced(path)) {
  248                       addServiced(path);
  249                       try {
  250                           warUpload.write(file);
  251                           // Perform new deployment
  252                           check(path);
  253                       } finally {
  254                           removeServiced(path);
  255                       }
  256                   }
  257                   break;
  258               }
  259           } catch(Exception e) {
  260               message = sm.getString
  261                   ("htmlManagerServlet.deployUploadFail", e.getMessage());
  262               log(message, e);
  263           } finally {
  264               if (warUpload != null) {
  265                   warUpload.delete();
  266               }
  267               warUpload = null;
  268           }
  269   
  270           list(request, response, message);
  271       }
  272   
  273       /**
  274        * Deploy an application for the specified path from the specified
  275        * web application archive.
  276        *
  277        * @param config URL of the context configuration file to be deployed
  278        * @param path Context path of the application to be deployed
  279        * @param war URL of the web application archive to be deployed
  280        * @return message String
  281        */
  282       protected String deployInternal(String config, String path, String war) {
  283   
  284           StringWriter stringWriter = new StringWriter();
  285           PrintWriter printWriter = new PrintWriter(stringWriter);
  286   
  287           super.deploy(printWriter, config, path, war, false);
  288   
  289           return stringWriter.toString();
  290       }
  291   
  292       /**
  293        * Render a HTML list of the currently active Contexts in our virtual host,
  294        * and memory and server status information.
  295        *
  296        * @param request The request
  297        * @param response The response
  298        * @param message a message to display
  299        */
  300       public void list(HttpServletRequest request,
  301                        HttpServletResponse response,
  302                        String message) throws IOException {
  303   
  304           if (debug >= 1)
  305               log("list: Listing contexts for virtual host '" +
  306                   host.getName() + "'");
  307   
  308           PrintWriter writer = response.getWriter();
  309   
  310           // HTML Header Section
  311           writer.print(Constants.HTML_HEADER_SECTION);
  312   
  313           // Body Header Section
  314           Object[] args = new Object[2];
  315           args[0] = request.getContextPath();
  316           args[1] = sm.getString("htmlManagerServlet.title");
  317           writer.print(MessageFormat.format
  318                        (Constants.BODY_HEADER_SECTION, args));
  319   
  320           // Message Section
  321           args = new Object[3];
  322           args[0] = sm.getString("htmlManagerServlet.messageLabel");
  323           if (message == null || message.length() == 0) {
  324               args[1] = "OK";
  325           } else {
  326               args[1] = RequestUtil.filter(message);
  327           }
  328           writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args));
  329   
  330           // Manager Section
  331           args = new Object[9];
  332           args[0] = sm.getString("htmlManagerServlet.manager");
  333           args[1] = response.encodeURL(request.getContextPath() + "/html/list");
  334           args[2] = sm.getString("htmlManagerServlet.list");
  335           args[3] = response.encodeURL
  336               (request.getContextPath() + "/" +
  337                sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
  338           args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
  339           args[5] = response.encodeURL
  340               (request.getContextPath() + "/" +
  341                sm.getString("htmlManagerServlet.helpManagerFile"));
  342           args[6] = sm.getString("htmlManagerServlet.helpManager");
  343           args[7] = response.encodeURL
  344               (request.getContextPath() + "/status");
  345           args[8] = sm.getString("statusServlet.title");
  346           writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args));
  347   
  348           // Apps Header Section
  349           args = new Object[6];
  350           args[0] = sm.getString("htmlManagerServlet.appsTitle");
  351           args[1] = sm.getString("htmlManagerServlet.appsPath");
  352           args[2] = sm.getString("htmlManagerServlet.appsName");
  353           args[3] = sm.getString("htmlManagerServlet.appsAvailable");
  354           args[4] = sm.getString("htmlManagerServlet.appsSessions");
  355           args[5] = sm.getString("htmlManagerServlet.appsTasks");
  356           writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
  357   
  358           // Apps Row Section
  359           // Create sorted map of deployed applications context paths.
  360           Container children[] = host.findChildren();
  361           String contextPaths[] = new String[children.length];
  362           for (int i = 0; i < children.length; i++)
  363               contextPaths[i] = children[i].getName();
  364   
  365           TreeMap sortedContextPathsMap = new TreeMap();
  366   
  367           for (int i = 0; i < contextPaths.length; i++) {
  368               String displayPath = contextPaths[i];
  369               sortedContextPathsMap.put(displayPath, contextPaths[i]);
  370           }
  371    
  372           String appsStart = sm.getString("htmlManagerServlet.appsStart");
  373           String appsStop = sm.getString("htmlManagerServlet.appsStop");
  374           String appsReload = sm.getString("htmlManagerServlet.appsReload");
  375           String appsUndeploy = sm.getString("htmlManagerServlet.appsUndeploy");
  376           String appsExpire = sm.getString("htmlManagerServlet.appsExpire");
  377   
  378           Iterator iterator = sortedContextPathsMap.entrySet().iterator();
  379           boolean isHighlighted = true;
  380           boolean isDeployed = true;
  381           String highlightColor = null;
  382   
  383           while (iterator.hasNext()) {
  384               // Bugzilla 34818, alternating row colors
  385               isHighlighted = !isHighlighted;
  386               if(isHighlighted) {
  387                   highlightColor = "#C3F3C3";
  388               } else {
  389                   highlightColor = "#FFFFFF";
  390               }
  391   
  392               Map.Entry entry = (Map.Entry) iterator.next();
  393               String displayPath = (String) entry.getKey();
  394               String contextPath = (String) entry.getValue();
  395               Context context = (Context) host.findChild(contextPath);
  396               if (displayPath.equals("")) {
  397                   displayPath = "/";
  398               }
  399   
  400               if (context != null ) {
  401                   try {
  402                       isDeployed = isDeployed(contextPath);
  403                   } catch (Exception e) {
  404                       // Assume false on failure for safety
  405                       isDeployed = false;
  406                   }
  407                   
  408                   args = new Object[7];
  409                   args[0] = URL_ENCODER.encode(displayPath);
  410                   args[1] = displayPath;
  411                   args[2] = context.getDisplayName();
  412                   if (args[2] == null) {
  413                       args[2] = "&nbsp;";
  414                   }
  415                   args[3] = new Boolean(context.getAvailable());
  416                   args[4] = response.encodeURL
  417                       (request.getContextPath() +
  418                        "/html/sessions?path=" + URL_ENCODER.encode(displayPath));
  419                   if (context.getManager() != null) {
  420                       args[5] = new Integer
  421                           (context.getManager().getActiveSessions());
  422                   } else {
  423                       args[5] = new Integer(0);
  424                   }
  425   
  426                   args[6] = highlightColor;
  427   
  428                   writer.print
  429                       (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args));
  430   
  431                   args = new Object[14];
  432                   args[0] = response.encodeURL
  433                       (request.getContextPath() +
  434                        "/html/start?path=" + URL_ENCODER.encode(displayPath));
  435                   args[1] = appsStart;
  436                   args[2] = response.encodeURL
  437                       (request.getContextPath() +
  438                        "/html/stop?path=" + URL_ENCODER.encode(displayPath));
  439                   args[3] = appsStop;
  440                   args[4] = response.encodeURL
  441                       (request.getContextPath() +
  442                        "/html/reload?path=" + URL_ENCODER.encode(displayPath));
  443                   args[5] = appsReload;
  444                   args[6] = response.encodeURL
  445                       (request.getContextPath() +
  446                        "/html/undeploy?path=" + URL_ENCODER.encode(displayPath));
  447                   args[7] = appsUndeploy;
  448                   
  449                   args[8] = response.encodeURL
  450                       (request.getContextPath() +
  451                        "/html/expire?path=" + URL_ENCODER.encode(displayPath));
  452                   args[9] = appsExpire;
  453                   args[10] = sm.getString("htmlManagerServlet.expire.explain");
  454                   Manager manager = context.getManager();
  455                   if (manager == null) {
  456                       args[11] = sm.getString("htmlManagerServlet.noManager");
  457                   } else {
  458                       args[11] = new Integer(
  459                               context.getManager().getMaxInactiveInterval()/60);
  460                   }
  461                   args[12] = sm.getString("htmlManagerServlet.expire.unit");
  462                   
  463                   args[13] = highlightColor;
  464   
  465                   if (context.getPath().equals(this.context.getPath())) {
  466                       writer.print(MessageFormat.format(
  467                           MANAGER_APP_ROW_BUTTON_SECTION, args));
  468                   } else if (context.getAvailable() && isDeployed) {
  469                       writer.print(MessageFormat.format(
  470                           STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  471                   } else if (context.getAvailable() && !isDeployed) {
  472                       writer.print(MessageFormat.format(
  473                           STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  474                   } else if (!context.getAvailable() && isDeployed) {
  475                       writer.print(MessageFormat.format(
  476                           STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  477                   } else {
  478                       writer.print(MessageFormat.format(
  479                           STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args));
  480                   }
  481   
  482               }
  483           }
  484   
  485           // Deploy Section
  486           args = new Object[7];
  487           args[0] = sm.getString("htmlManagerServlet.deployTitle");
  488           args[1] = sm.getString("htmlManagerServlet.deployServer");
  489           args[2] = response.encodeURL(request.getContextPath() + "/html/deploy");
  490           args[3] = sm.getString("htmlManagerServlet.deployPath");
  491           args[4] = sm.getString("htmlManagerServlet.deployConfig");
  492           args[5] = sm.getString("htmlManagerServlet.deployWar");
  493           args[6] = sm.getString("htmlManagerServlet.deployButton");
  494           writer.print(MessageFormat.format(DEPLOY_SECTION, args));
  495   
  496           args = new Object[4];
  497           args[0] = sm.getString("htmlManagerServlet.deployUpload");
  498           args[1] = response.encodeURL(request.getContextPath() + "/html/upload");
  499           args[2] = sm.getString("htmlManagerServlet.deployUploadFile");
  500           args[3] = sm.getString("htmlManagerServlet.deployButton");
  501           writer.print(MessageFormat.format(UPLOAD_SECTION, args));
  502   
  503           // Diagnostics section
  504           args = new Object[5];
  505           args[0] = sm.getString("htmlManagerServlet.diagnosticsTitle");
  506           args[1] = sm.getString("htmlManagerServlet.diagnosticsLeak");
  507           args[2] = response.encodeURL(request.getContextPath() +
  508                   "/html/findleaks");
  509           args[3] = sm.getString("htmlManagerServlet.diagnosticsLeakWarning");
  510           args[4] = sm.getString("htmlManagerServlet.diagnosticsLeakButton");
  511           writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args));
  512   
  513           // Server Header Section
  514           args = new Object[7];
  515           args[0] = sm.getString("htmlManagerServlet.serverTitle");
  516           args[1] = sm.getString("htmlManagerServlet.serverVersion");
  517           args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
  518           args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
  519           args[4] = sm.getString("htmlManagerServlet.serverOSName");
  520           args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
  521           args[6] = sm.getString("htmlManagerServlet.serverOSArch");
  522           writer.print(MessageFormat.format
  523                        (Constants.SERVER_HEADER_SECTION, args));
  524   
  525           // Server Row Section
  526           args = new Object[6];
  527           args[0] = ServerInfo.getServerInfo();
  528           args[1] = System.getProperty("java.runtime.version");
  529           args[2] = System.getProperty("java.vm.vendor");
  530           args[3] = System.getProperty("os.name");
  531           args[4] = System.getProperty("os.version");
  532           args[5] = System.getProperty("os.arch");
  533           writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args));
  534   
  535           // HTML Tail Section
  536           writer.print(Constants.HTML_TAIL_SECTION);
  537   
  538           // Finish up the response
  539           writer.flush();
  540           writer.close();
  541       }
  542   
  543       /**
  544        * Reload the web application at the specified context path.
  545        *
  546        * @see ManagerServlet#reload(PrintWriter, String)
  547        *
  548        * @param path Context path of the application to be restarted
  549        * @return message String
  550        */
  551       protected String reload(String path) {
  552   
  553           StringWriter stringWriter = new StringWriter();
  554           PrintWriter printWriter = new PrintWriter(stringWriter);
  555   
  556           super.reload(printWriter, path);
  557   
  558           return stringWriter.toString();
  559       }
  560   
  561       /**
  562        * Undeploy the web application at the specified context path.
  563        *
  564        * @see ManagerServlet#undeploy(PrintWriter, String)
  565        *
  566        * @param path Context path of the application to be undeployd
  567        * @return message String
  568        */
  569       protected String undeploy(String path) {
  570   
  571           StringWriter stringWriter = new StringWriter();
  572           PrintWriter printWriter = new PrintWriter(stringWriter);
  573   
  574           super.undeploy(printWriter, path);
  575   
  576           return stringWriter.toString();
  577       }
  578   
  579       /**
  580        * Display session information and invoke list.
  581        *
  582        * @see ManagerServlet#sessions(PrintWriter, String, int)
  583        *
  584        * @param path Context path of the application to list session information
  585        * @param idle Expire all sessions with idle time &ge; idle for this context
  586        * @return message String
  587        */
  588       public String sessions(String path, int idle) {
  589   
  590           StringWriter stringWriter = new StringWriter();
  591           PrintWriter printWriter = new PrintWriter(stringWriter);
  592   
  593           super.sessions(printWriter, path, idle);
  594   
  595           return stringWriter.toString();
  596       }
  597   
  598       /**
  599        * Display session information and invoke list.
  600        *
  601        * @see ManagerServlet#sessions(PrintWriter, String)
  602        *
  603        * @param path Context path of the application to list session information
  604        * @return message String
  605        */
  606       public String sessions(String path) {
  607   
  608           return sessions(path, -1);
  609       }
  610   
  611       /**
  612        * Start the web application at the specified context path.
  613        *
  614        * @see ManagerServlet#start(PrintWriter, String)
  615        *
  616        * @param path Context path of the application to be started
  617        * @return message String
  618        */
  619       public String start(String path) {
  620   
  621           StringWriter stringWriter = new StringWriter();
  622           PrintWriter printWriter = new PrintWriter(stringWriter);
  623   
  624           super.start(printWriter, path);
  625   
  626           return stringWriter.toString();
  627       }
  628   
  629       /**
  630        * Stop the web application at the specified context path.
  631        *
  632        * @see ManagerServlet#stop(PrintWriter, String)
  633        *
  634        * @param path Context path of the application to be stopped
  635        * @return message String
  636        */
  637       protected String stop(String path) {
  638   
  639           StringWriter stringWriter = new StringWriter();
  640           PrintWriter printWriter = new PrintWriter(stringWriter);
  641   
  642           super.stop(printWriter, path);
  643   
  644           return stringWriter.toString();
  645       }
  646       
  647       /**
  648        * Find potential memory leaks caused by web application reload.
  649        *
  650        * @see ManagerServlet#findleaks(PrintWriter) 
  651        *
  652        * @return message String
  653        */
  654       protected String findleaks() {
  655   
  656           StringBuilder msg = new StringBuilder();
  657   
  658           StringWriter stringWriter = new StringWriter();
  659           PrintWriter printWriter = new PrintWriter(stringWriter);
  660   
  661           super.findleaks(printWriter);
  662   
  663           if (stringWriter.getBuffer().length() > 0) {
  664               msg.append(sm.getString("htmlManagerServlet.findleaksList"));
  665               msg.append(stringWriter.toString());
  666           } else {
  667               msg.append(sm.getString("htmlManagerServlet.findleaksNone"));
  668           }
  669   
  670           return msg.toString();
  671       }
  672   
  673   
  674       /**
  675        * @see javax.servlet.Servlet#getServletInfo()
  676        */
  677       public String getServletInfo() {
  678           return "HTMLManagerServlet, Copyright (c) 1999-2010, The Apache Software Foundation";
  679       }   
  680       
  681       /**
  682        * @see javax.servlet.GenericServlet#init()
  683        */
  684       public void init() throws ServletException {
  685           super.init();
  686       }   
  687   
  688       // ------------------------------------------------ Sessions administration
  689   
  690       /**
  691        *
  692        * Extract the expiration request parameter
  693        * 
  694        * @param path
  695        * @param req
  696        */
  697       protected String expireSessions(String path, HttpServletRequest req) {
  698           int idle = -1;
  699           String idleParam = req.getParameter("idle");
  700           if (idleParam != null) {
  701               try {
  702                   idle = Integer.parseInt(idleParam);
  703               } catch (NumberFormatException e) {
  704                   log("Could not parse idle parameter to an int: " + idleParam);
  705               }
  706           }
  707           return sessions(path, idle);
  708       }
  709   
  710       /**
  711        * 
  712        * @param req
  713        * @param resp
  714        * @throws ServletException
  715        * @throws IOException 
  716        */
  717       protected void doSessions(String path, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  718           req.setAttribute("path", path);
  719           String action = req.getParameter("action");
  720           if (debug >= 1) {
  721               log("sessions: Session action '" + action + "' for web application at '" + path + "'");
  722           }
  723           if ("sessionDetail".equals(action)) {
  724   	        String sessionId = req.getParameter("sessionId");
  725   	        displaySessionDetailPage(req, resp, path, sessionId);
  726   	        return;
  727           } else if ("invalidateSessions".equals(action)) {
  728               String[] sessionIds = req.getParameterValues("sessionIds");
  729               int i = invalidateSessions(path, sessionIds);
  730               req.setAttribute(APPLICATION_MESSAGE, "" + i + " sessions invalidated.");
  731           } else if ("removeSessionAttribute".equals(action)) {
  732               String sessionId = req.getParameter("sessionId");
  733               String name = req.getParameter("attributeName");
  734               boolean removed = removeSessionAttribute(path, sessionId, name);
  735               String outMessage = removed ? "Session attribute '" + name + "' removed." : "Session did not contain any attribute named '" + name + "'";
  736               req.setAttribute(APPLICATION_MESSAGE, outMessage);
  737               resp.sendRedirect(resp.encodeRedirectURL(req.getRequestURL().append("?path=").append(path).append("&action=sessionDetail&sessionId=").append(sessionId).toString()));
  738               return;
  739           } // else
  740           displaySessionsListPage(path, req, resp);
  741       }
  742   
  743       protected Session[] getSessionsForPath(String path) {
  744           if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
  745               throw new IllegalArgumentException(sm.getString("managerServlet.invalidPath",
  746                                           RequestUtil.filter(path)));
  747           }
  748           String displayPath = path;
  749           if( path.equals("/") )
  750               path = "";
  751           Context context = (Context) host.findChild(path);
  752           if (null == context) {
  753               throw new IllegalArgumentException(sm.getString("managerServlet.noContext",
  754                                           RequestUtil.filter(displayPath)));
  755           }
  756           Session[] sessions = context.getManager().findSessions();
  757           return sessions;
  758       }
  759       protected Session getSessionForPathAndId(String path, String id) throws IOException {
  760           if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
  761               throw new IllegalArgumentException(sm.getString("managerServlet.invalidPath",
  762                                           RequestUtil.filter(path)));
  763           }
  764           String displayPath = path;
  765           if( path.equals("/") )
  766               path = "";
  767           Context context = (Context) host.findChild(path);
  768           if (null == context) {
  769               throw new IllegalArgumentException(sm.getString("managerServlet.noContext",
  770                                           RequestUtil.filter(displayPath)));
  771           }
  772           Session session = context.getManager().findSession(id);
  773           return session;
  774       }
  775   
  776       /**
  777        * 
  778        * @param req
  779        * @param resp
  780        * @throws ServletException
  781        * @throws IOException
  782        */
  783       protected void displaySessionsListPage(String path, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  784           List/*<Session>*/ activeSessions = Arrays.asList(getSessionsForPath(path));
  785           String sortBy = req.getParameter("sort");
  786           String orderBy = null;
  787           if (null != sortBy && !"".equals(sortBy.trim())) {
  788               Comparator comparator = getComparator(sortBy);
  789               if (comparator != null) {
  790                   orderBy = req.getParameter("order");
  791                   if ("DESC".equalsIgnoreCase(orderBy)) {
  792                       comparator = new ReverseComparator(comparator);
  793                       // orderBy = "ASC";
  794                   } else {
  795                       //orderBy = "DESC";
  796                   }
  797                   try {
  798   					Collections.sort(activeSessions, comparator);
  799   				} catch (IllegalStateException ise) {
  800   					// at least 1 of the sessions is invalidated
  801   					req.setAttribute(APPLICATION_ERROR, "Can't sort session list: one session is invalidated");
  802   				}
  803               } else {
  804                   log("WARNING: unknown sort order: " + sortBy);
  805               }
  806           }
  807           // keep sort order
  808           req.setAttribute("sort", sortBy);
  809           req.setAttribute("order", orderBy);
  810           req.setAttribute("activeSessions", activeSessions);
  811           //strong>NOTE</strong> - This header will be overridden
  812           // automatically if a <code>RequestDispatcher.forward()</code> call is
  813           // ultimately invoked.
  814           resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
  815           resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
  816           resp.setDateHeader("Expires", 0); // 0 means now
  817           getServletContext().getRequestDispatcher(sessionsListJspPath).include(req, resp);
  818       }
  819   
  820       /**
  821        * 
  822        * @param req
  823        * @param resp
  824        * @throws ServletException
  825        * @throws IOException
  826        */
  827       protected void displaySessionDetailPage(HttpServletRequest req, HttpServletResponse resp, String path, String sessionId) throws ServletException, IOException {
  828           Session session = getSessionForPathAndId(path, sessionId);
  829           //strong>NOTE</strong> - This header will be overridden
  830           // automatically if a <code>RequestDispatcher.forward()</code> call is
  831           // ultimately invoked.
  832           resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
  833           resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
  834           resp.setDateHeader("Expires", 0); // 0 means now
  835           req.setAttribute("currentSession", session);
  836           getServletContext().getRequestDispatcher(sessionDetailJspPath).include(req, resp);
  837       }
  838   
  839       /**
  840        * Invalidate HttpSessions
  841        * @param sessionIds
  842        * @return number of invalidated sessions
  843        * @throws IOException 
  844        */
  845       public int invalidateSessions(String path, String[] sessionIds) throws IOException {
  846           if (null == sessionIds) {
  847               return 0;
  848           }
  849           int nbAffectedSessions = 0;
  850           for (int i = 0; i < sessionIds.length; ++i) {
  851               String sessionId = sessionIds[i];
  852               HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
  853               if (null == session) {
  854                   // Shouldn't happen, but let's play nice...
  855               	if (debug >= 1) {
  856               		log("WARNING: can't invalidate null session " + sessionId);
  857               	}
  858                   continue;
  859               }
  860               try {
  861   				session.invalidate();
  862   				++nbAffectedSessions;
  863   	            if (debug >= 1) {
  864   	                log("Invalidating session id " + sessionId);
  865   	            }
  866   			} catch (IllegalStateException ise) {
  867   				if (debug >= 1) {
  868   					log("Can't invalidate already invalidated session id " + sessionId);
  869   				}
  870   			}
  871           }
  872           return nbAffectedSessions;
  873       }
  874   
  875       /**
  876        * Removes an attribute from an HttpSession
  877        * @param sessionId
  878        * @param attributeName
  879        * @return true if there was an attribute removed, false otherwise
  880        * @throws IOException 
  881        */
  882       public boolean removeSessionAttribute(String path, String sessionId, String attributeName) throws IOException {
  883           HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
  884           if (null == session) {
  885               // Shouldn't happen, but let's play nice...
  886           	if (debug >= 1) {
  887           		log("WARNING: can't remove attribute '" + attributeName + "' for null session " + sessionId);
  888           	}
  889               return false;
  890           }
  891           boolean wasPresent = (null != session.getAttribute(attributeName));
  892           try {
  893               session.removeAttribute(attributeName);
  894           } catch (IllegalStateException ise) {
  895           	if (debug >= 1) {
  896           		log("Can't remote attribute '" + attributeName + "' for invalidated session id " + sessionId);
  897           	}
  898           }
  899           return wasPresent;
  900       }
  901   
  902       /**
  903        * Sets the maximum inactive interval (session timeout) an HttpSession
  904        * @param sessionId
  905        * @param maxInactiveInterval in seconds
  906        * @return old value for maxInactiveInterval
  907        * @throws IOException 
  908        */
  909       public int setSessionMaxInactiveInterval(String path, String sessionId, int maxInactiveInterval) throws IOException {
  910           HttpSession session = getSessionForPathAndId(path, sessionId).getSession();
  911           if (null == session) {
  912               // Shouldn't happen, but let's play nice...
  913           	if (debug >= 1) {
  914           		log("WARNING: can't set timout for null session " + sessionId);
  915           	}
  916               return 0;
  917           }
  918           try {
  919   			int oldMaxInactiveInterval = session.getMaxInactiveInterval();
  920   			session.setMaxInactiveInterval(maxInactiveInterval);
  921   			return oldMaxInactiveInterval;
  922           } catch (IllegalStateException ise) {
  923           	if (debug >= 1) {
  924           		log("Can't set MaxInactiveInterval '" + maxInactiveInterval + "' for invalidated session id " + sessionId);
  925           	}
  926           	return 0;
  927   		}
  928       }
  929   
  930       protected Comparator getComparator(String sortBy) {
  931           Comparator comparator = null;
  932           if ("CreationTime".equalsIgnoreCase(sortBy)) {
  933               comparator = new BaseSessionComparator() {
  934                   public Comparable getComparableObject(Session session) {
  935                       return new Date(session.getCreationTime());
  936                   }
  937               };
  938           } else if ("id".equalsIgnoreCase(sortBy)) {
  939               comparator = new BaseSessionComparator() {
  940                   public Comparable getComparableObject(Session session) {
  941                       return session.getId();
  942                   }
  943               };
  944           } else if ("LastAccessedTime".equalsIgnoreCase(sortBy)) {
  945               comparator = new BaseSessionComparator() {
  946                   public Comparable getComparableObject(Session session) {
  947                       return new Date(session.getLastAccessedTime());
  948                   }
  949               };
  950           } else if ("MaxInactiveInterval".equalsIgnoreCase(sortBy)) {
  951               comparator = new BaseSessionComparator() {
  952                   public Comparable getComparableObject(Session session) {
  953                       return new Date(session.getMaxInactiveInterval());
  954                   }
  955               };
  956           } else if ("new".equalsIgnoreCase(sortBy)) {
  957               comparator = new BaseSessionComparator() {
  958                   public Comparable getComparableObject(Session session) {
  959                       return Boolean.valueOf(session.getSession().isNew());
  960                   }
  961               };
  962           } else if ("locale".equalsIgnoreCase(sortBy)) {
  963               comparator = new BaseSessionComparator() {
  964                   public Comparable getComparableObject(Session session) {
  965                       return JspHelper.guessDisplayLocaleFromSession(session);
  966                   }
  967               };
  968           } else if ("user".equalsIgnoreCase(sortBy)) {
  969               comparator = new BaseSessionComparator() {
  970                   public Comparable getComparableObject(Session session) {
  971                       return JspHelper.guessDisplayUserFromSession(session);
  972                   }
  973               };
  974           } else if ("UsedTime".equalsIgnoreCase(sortBy)) {
  975               comparator = new BaseSessionComparator() {
  976                   public Comparable getComparableObject(Session session) {
  977                       return new Date(SessionUtils.getUsedTimeForSession(session));
  978                   }
  979               };
  980           } else if ("InactiveTime".equalsIgnoreCase(sortBy)) {
  981               comparator = new BaseSessionComparator() {
  982                   public Comparable getComparableObject(Session session) {
  983                       return new Date(SessionUtils.getInactiveTimeForSession(session));
  984                   }
  985               };
  986           } else if ("TTL".equalsIgnoreCase(sortBy)) {
  987               comparator = new BaseSessionComparator() {
  988                   public Comparable getComparableObject(Session session) {
  989                       return new Date(SessionUtils.getTTLForSession(session));
  990                   }
  991               };
  992           }
  993           //TODO: complete this to TTL, etc.
  994           return comparator;
  995       }
  996   
  997       // ------------------------------------------------------ Private Constants
  998   
  999       // These HTML sections are broken in relatively small sections, because of
 1000       // limited number of subsitutions MessageFormat can process
 1001       // (maximium of 10).
 1002   
 1003       private static final String APPS_HEADER_SECTION =
 1004           "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
 1005           "<tr>\n" +
 1006           " <td colspan=\"5\" class=\"title\">{0}</td>\n" +
 1007           "</tr>\n" +
 1008           "<tr>\n" +
 1009           " <td class=\"header-left\"><small>{1}</small></td>\n" +
 1010           " <td class=\"header-left\"><small>{2}</small></td>\n" +
 1011           " <td class=\"header-center\"><small>{3}</small></td>\n" +
 1012           " <td class=\"header-center\"><small>{4}</small></td>\n" +
 1013           " <td class=\"header-left\"><small>{5}</small></td>\n" +
 1014           "</tr>\n";
 1015   
 1016       private static final String APPS_ROW_DETAILS_SECTION =
 1017           "<tr>\n" +
 1018           " <td class=\"row-left\" bgcolor=\"{6}\" rowspan=\"2\"><small><a href=\"{0}\">{1}</a>" +
 1019           "</small></td>\n" +
 1020           " <td class=\"row-left\" bgcolor=\"{6}\" rowspan=\"2\"><small>{2}</small></td>\n" +
 1021           " <td class=\"row-center\" bgcolor=\"{6}\" rowspan=\"2\"><small>{3}</small></td>\n" +
 1022           " <td class=\"row-center\" bgcolor=\"{6}\" rowspan=\"2\">" +
 1023           "<small><a href=\"{4}\" target=\"_blank\">{5}</a></small></td>\n";
 1024   
 1025       private static final String MANAGER_APP_ROW_BUTTON_SECTION =
 1026           " <td class=\"row-left\" bgcolor=\"{13}\">\n" +
 1027           "  <small>\n" +
 1028           "  &nbsp;{1}&nbsp;\n" +
 1029           "  &nbsp;{3}&nbsp;\n" +
 1030           "  &nbsp;{5}&nbsp;\n" +
 1031           "  &nbsp;{7}&nbsp;\n" +
 1032           "  </small>\n" +
 1033           " </td>\n" +
 1034           "</tr><tr>\n" +
 1035           " <td class=\"row-left\" bgcolor=\"{13}\">\n" +
 1036           "  <form method=\"POST\" action=\"{8}\">\n" +
 1037           "  <small>\n" +
 1038           "  &nbsp;<input type=\"submit\" value=\"{9}\">&nbsp;{10}&nbsp;<input type=\"text\" name=\"idle\" size=\"5\" value=\"{11}\">&nbsp;{12}&nbsp;\n" +
 1039           "  </small>\n" +
 1040           "  </form>\n" +
 1041           " </td>\n" +
 1042           "</tr>\n";
 1043   
 1044       private static final String STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION =
 1045           " <td class=\"row-left\" bgcolor=\"{13}\">\n" +
 1046           "  <small>\n" +
 1047           "  &nbsp;{1}&nbsp;\n" +
 1048           "  &nbsp;<a href=\"{2}\" onclick=\"return(confirm('''Are you sure?'''))\">{3}</a>&nbsp;\n" +
 1049           "  &nbsp;<a href=\"{4}\" onclick=\"return(confirm('''Are you sure?'''))\">{5}</a>&nbsp;\n" +
 1050           "  &nbsp;<a href=\"{6}\" onclick=\"return(confirm('''Are you sure?'''))\">{7}</a>&nbsp;\n" +
 1051           "  </small>\n" +
 1052           " </td>\n" +
 1053           " </tr><tr>\n" +
 1054           " <td class=\"row-left\" bgcolor=\"{13}\">\n" +
 1055           "  <form method=\"POST\" action=\"{8}\">\n" +
 1056           "  <small>\n" +
 1057           "  &nbsp;<input type=\"submit\" value=\"{9}\">&nbsp;{10}&nbsp;<input type=\"text\" name=\"idle\" size=\"5\" value=\"{11}\">&nbsp;{12}&nbsp;\n" +
 1058           "  </small>\n" +
 1059           "  </form>\n" +
 1060           " </td>\n" +
 1061           "</tr>\n";
 1062   
 1063       private static final String STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION =
 1064           " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n" +
 1065           "  <small>\n" +
 1066           "  &nbsp;<a href=\"{0}\" onclick=\"return(confirm('''Are you sure?'''))\">{1}</a>&nbsp;\n" +
 1067           "  &nbsp;{3}&nbsp;\n" +
 1068           "  &nbsp;{5}&nbsp;\n" +
 1069           "  &nbsp;<a href=\"{6}\" onclick=\"return(confirm('''Are you sure?  This will delete the application.'''))\">{7}</a>&nbsp;\n" +
 1070           "  </small>\n" +
 1071           " </td>\n" +
 1072           "</tr>\n<tr></tr>\n";
 1073   
 1074       private static final String STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION =
 1075           " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n" +
 1076           "  <small>\n" +
 1077           "  &nbsp;{1}&nbsp;\n" +
 1078           "  &nbsp;<a href=\"{2}\" onclick=\"return(confirm('''Are you sure?'''))\">{3}</a>&nbsp;\n" +
 1079           "  &nbsp;<a href=\"{4}\" onclick=\"return(confirm('''Are you sure?'''))\">{5}</a>&nbsp;\n" +
 1080           "  &nbsp;{7}&nbsp;\n" +
 1081           "  </small>\n" +
 1082           " </td>\n" +
 1083           "</tr>\n<tr></tr>\n";
 1084   
 1085       private static final String STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION =
 1086           " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n" +
 1087           "  <small>\n" +
 1088           "  &nbsp;<a href=\"{0}\" onclick=\"return(confirm('''Are you sure?'''))\">{1}</a>&nbsp;\n" +
 1089           "  &nbsp;{3}&nbsp;\n" +
 1090           "  &nbsp;{5}&nbsp;\n" +
 1091           "  &nbsp;{7}&nbsp;\n" +
 1092           "  </small>\n" +
 1093           " </td>\n" +
 1094           "</tr>\n<tr></tr>\n";
 1095   
 1096       private static final String DEPLOY_SECTION =
 1097           "</table>\n" +
 1098           "<br>\n" +
 1099           "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
 1100           "<tr>\n" +
 1101           " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
 1102           "</tr>\n" +
 1103           "<tr>\n" +
 1104           " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
 1105           "</tr>\n" +
 1106           "<tr>\n" +
 1107           " <td colspan=\"2\">\n" +
 1108           "<form method=\"get\" action=\"{2}\">\n" +
 1109           "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
 1110           "<tr>\n" +
 1111           " <td class=\"row-right\">\n" +
 1112           "  <small>{3}</small>\n" +
 1113           " </td>\n" +
 1114           " <td class=\"row-left\">\n" +
 1115           "  <input type=\"text\" name=\"deployPath\" size=\"20\">\n" +
 1116           " </td>\n" +
 1117           "</tr>\n" +
 1118           "<tr>\n" +
 1119           " <td class=\"row-right\">\n" +
 1120           "  <small>{4}</small>\n" +
 1121           " </td>\n" +
 1122           " <td class=\"row-left\">\n" +
 1123           "  <input type=\"text\" name=\"deployConfig\" size=\"20\">\n" +
 1124           " </td>\n" +
 1125           "</tr>\n" +
 1126           "<tr>\n" +
 1127           " <td class=\"row-right\">\n" +
 1128           "  <small>{5}</small>\n" +
 1129           " </td>\n" +
 1130           " <td class=\"row-left\">\n" +
 1131           "  <input type=\"text\" name=\"deployWar\" size=\"40\">\n" +
 1132           " </td>\n" +
 1133           "</tr>\n" +
 1134           "<tr>\n" +
 1135           " <td class=\"row-right\">\n" +
 1136           "  &nbsp;\n" +
 1137           " </td>\n" +
 1138           " <td class=\"row-left\">\n" +
 1139           "  <input type=\"submit\" value=\"{6}\">\n" +
 1140           " </td>\n" +
 1141           "</tr>\n" +
 1142           "</table>\n" +
 1143           "</form>\n" +
 1144           "</td>\n" +
 1145           "</tr>\n";
 1146   
 1147       private static final String UPLOAD_SECTION =
 1148           "<tr>\n" +
 1149           " <td colspan=\"2\" class=\"header-left\"><small>{0}</small></td>\n" +
 1150           "</tr>\n" +
 1151           "<tr>\n" +
 1152           " <td colspan=\"2\">\n" +
 1153           "<form action=\"{1}\" method=\"post\" " +
 1154           "enctype=\"multipart/form-data\">\n" +
 1155           "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
 1156           "<tr>\n" +
 1157           " <td class=\"row-right\">\n" +
 1158           "  <small>{2}</small>\n" +
 1159           " </td>\n" +
 1160           " <td class=\"row-left\">\n" +
 1161           "  <input type=\"file\" name=\"deployWar\" size=\"40\">\n" +
 1162           " </td>\n" +
 1163           "</tr>\n" +
 1164           "<tr>\n" +
 1165           " <td class=\"row-right\">\n" +
 1166           "  &nbsp;\n" +
 1167           " </td>\n" +
 1168           " <td class=\"row-left\">\n" +
 1169           "  <input type=\"submit\" value=\"{3}\">\n" +
 1170           " </td>\n" +
 1171           "</tr>\n" +
 1172           "</table>\n" +
 1173           "</form>\n" +
 1174           "</table>\n" +
 1175           "<br>\n" +
 1176           "\n";
 1177   
 1178       private static final String DIAGNOSTICS_SECTION =
 1179           "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
 1180           "<tr>\n" +
 1181           " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
 1182           "</tr>\n" +
 1183           "<tr>\n" +
 1184           " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
 1185           "</tr>\n" +
 1186           "<tr>\n" +
 1187           " <td colspan=\"2\">\n" +
 1188           "<form method=\"post\" action=\"{2}\">\n" +
 1189           "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
 1190           "<tr>\n" +
 1191           " <td class=\"row-left\">\n" +
 1192           "  <input type=\"submit\" value=\"{4}\">\n" +
 1193           " </td>\n" +
 1194           " <td class=\"row-left\">\n" +
 1195           "  <small>{3}</small>\n" +
 1196           " </td>\n" +
 1197           "</tr>\n" +
 1198           "</table>\n" +
 1199           "</form>\n" +
 1200           "</td>\n" +
 1201           "</tr>\n" +
 1202           "</table>\n" +
 1203           "<br>";
 1204   
 1205   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » manager » [javadoc | source]