/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.apache.catalina.manager;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.Part;

import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.DistributedManager;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.manager.util.BaseSessionComparator;
import org.apache.catalina.manager.util.SessionUtils;
import org.apache.catalina.util.ContextName;
import org.apache.catalina.util.ServerInfo;
import org.apache.catalina.util.URLEncoder;
import org.apache.tomcat.util.res.StringManager;
import org.apache.tomcat.util.security.Escape;

Servlet that enables remote management of the web applications deployed within the same virtual host as this web application is. Normally, this functionality will be protected by a security constraint in the web application deployment descriptor. However, this requirement can be relaxed during testing.

The difference between the ManagerServlet and this Servlet is that this Servlet prints out an HTML interface which makes it easier to administrate.

However if you use a software that parses the output of ManagerServlet you won't be able to upgrade to this Servlet since the output are not in the same format ar from ManagerServlet

Author:Bip Thelin, Malcolm Edgar, Glenn L. Nielsen
See Also:
/** * Servlet that enables remote management of the web applications deployed * within the same virtual host as this web application is. Normally, this * functionality will be protected by a security constraint in the web * application deployment descriptor. However, this requirement can be * relaxed during testing. * <p> * The difference between the <code>ManagerServlet</code> and this * Servlet is that this Servlet prints out an HTML interface which * makes it easier to administrate. * <p> * However if you use a software that parses the output of * <code>ManagerServlet</code> you won't be able to upgrade * to this Servlet since the output are not in the * same format ar from <code>ManagerServlet</code> * * @author Bip Thelin * @author Malcolm Edgar * @author Glenn L. Nielsen * @see ManagerServlet */
public final class HTMLManagerServlet extends ManagerServlet { private static final long serialVersionUID = 1L; static final String APPLICATION_MESSAGE = "message"; static final String APPLICATION_ERROR = "error"; static final String sessionsListJspPath = "/WEB-INF/jsp/sessionsList.jsp"; static final String sessionDetailJspPath = "/WEB-INF/jsp/sessionDetail.jsp"; static final String connectorCiphersJspPath = "/WEB-INF/jsp/connectorCiphers.jsp"; static final String connectorCertsJspPath = "/WEB-INF/jsp/connectorCerts.jsp"; static final String connectorTrustedCertsJspPath = "/WEB-INF/jsp/connectorTrustedCerts.jsp"; private boolean showProxySessions = false; // --------------------------------------------------------- Public Methods
Process a GET request for the specified resource.
Params:
  • request – The servlet request we are processing
  • response – The servlet response we are creating
Throws:
/** * Process a GET request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */
@Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need // By obtaining the command from the pathInfo, per-command security can // be configured in web.xml String command = request.getPathInfo(); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; // Process the requested command if (command == null || command.equals("/")) { // No command == list } else if (command.equals("/list")) { // List always displayed - nothing to do here } else if (command.equals("/sessions")) { try { doSessions(cn, request, response, smClient); return; } catch (Exception e) { log(sm.getString("htmlManagerServlet.error.sessions", cn), e); message = smClient.getString("managerServlet.exception", e.toString()); } } else if (command.equals("/sslConnectorCiphers")) { sslConnectorCiphers(request, response, smClient); } else if (command.equals("/sslConnectorCerts")) { sslConnectorCerts(request, response, smClient); } else if (command.equals("/sslConnectorTrustedCerts")) { sslConnectorTrustedCerts(request, response, smClient); } else if (command.equals("/upload") || command.equals("/deploy") || command.equals("/reload") || command.equals("/undeploy") || command.equals("/expire") || command.equals("/start") || command.equals("/stop")) { message = smClient.getString("managerServlet.postCommand", command); } else { message = smClient.getString("managerServlet.unknownCommand", command); } list(request, response, message, smClient); }
Process a POST request for the specified resource.
Params:
  • request – The servlet request we are processing
  • response – The servlet response we are creating
Throws:
/** * Process a POST request for the specified resource. * * @param request The servlet request we are processing * @param response The servlet response we are creating * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs */
@Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { StringManager smClient = StringManager.getManager( Constants.Package, request.getLocales()); // Identify the request parameters that we need // By obtaining the command from the pathInfo, per-command security can // be configured in web.xml String command = request.getPathInfo(); String path = request.getParameter("path"); ContextName cn = null; if (path != null) { cn = new ContextName(path, request.getParameter("version")); } String deployPath = request.getParameter("deployPath"); String deployWar = request.getParameter("deployWar"); String deployConfig = request.getParameter("deployConfig"); ContextName deployCn = null; if (deployPath != null && deployPath.length() > 0) { deployCn = new ContextName(deployPath, request.getParameter("deployVersion")); } else if (deployConfig != null && deployConfig.length() > 0) { deployCn = ContextName.extractFromPath(deployConfig); } else if (deployWar != null && deployWar.length() > 0) { deployCn = ContextName.extractFromPath(deployWar); } String tlsHostName = request.getParameter("tlsHostName"); // Prepare our output writer to generate the response message response.setContentType("text/html; charset=" + Constants.CHARSET); String message = ""; if (command == null || command.length() == 0) { // No command == list // List always displayed -> do nothing } else if (command.equals("/upload")) { message = upload(request, smClient); } else if (command.equals("/deploy")) { message = deployInternal(deployConfig, deployCn, deployWar, smClient); } else if (command.equals("/reload")) { message = reload(cn, smClient); } else if (command.equals("/undeploy")) { message = undeploy(cn, smClient); } else if (command.equals("/expire")) { message = expireSessions(cn, request, smClient); } else if (command.equals("/start")) { message = start(cn, smClient); } else if (command.equals("/stop")) { message = stop(cn, smClient); } else if (command.equals("/findleaks")) { message = findleaks(smClient); } else if (command.equals("/sslReload")) { message = sslReload(tlsHostName, smClient); } else { // Try GET doGet(request,response); return; } list(request, response, message, smClient); } protected String upload(HttpServletRequest request, StringManager smClient) { String message = ""; try { while (true) { Part warPart = request.getPart("deployWar"); if (warPart == null) { message = smClient.getString( "htmlManagerServlet.deployUploadNoFile"); break; } String filename = warPart.getSubmittedFileName(); if (!filename.toLowerCase(Locale.ENGLISH).endsWith(".war")) { message = smClient.getString( "htmlManagerServlet.deployUploadNotWar", filename); break; } // Get the filename if uploaded name includes a path if (filename.lastIndexOf('\\') >= 0) { filename = filename.substring(filename.lastIndexOf('\\') + 1); } if (filename.lastIndexOf('/') >= 0) { filename = filename.substring(filename.lastIndexOf('/') + 1); } // Identify the appBase of the owning Host of this Context // (if any) File file = new File(host.getAppBaseFile(), filename); if (file.exists()) { message = smClient.getString( "htmlManagerServlet.deployUploadWarExists", filename); break; } ContextName cn = new ContextName(filename, true); String name = cn.getName(); if ((host.findChild(name) != null) && !isDeployed(name)) { message = smClient.getString( "htmlManagerServlet.deployUploadInServerXml", filename); break; } if (isServiced(name)) { message = smClient.getString("managerServlet.inService", name); } else { addServiced(name); try { warPart.write(file.getAbsolutePath()); // Perform new deployment check(name); } finally { removeServiced(name); } } break; } } catch(Exception e) { message = smClient.getString ("htmlManagerServlet.deployUploadFail", e.getMessage()); log(message, e); } return message; }
Deploy an application for the specified path from the specified web application archive.
Params:
  • config – URL of the context configuration file to be deployed
  • cn – Name of the application to be deployed
  • war – URL of the web application archive to be deployed
  • smClient – internationalized strings
Returns:message String
/** * Deploy an application for the specified path from the specified * web application archive. * * @param config URL of the context configuration file to be deployed * @param cn Name of the application to be deployed * @param war URL of the web application archive to be deployed * @param smClient internationalized strings * @return message String */
protected String deployInternal(String config, ContextName cn, String war, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.deploy(printWriter, config, cn, war, false, smClient); return stringWriter.toString(); }
Render an HTML list of the currently active Contexts in our virtual host, and memory and server status information.
Params:
  • request – The request
  • response – The response
  • message – a message to display
  • smClient – internationalized strings
Throws:
/** * Render an HTML list of the currently active Contexts in our virtual host, * and memory and server status information. * * @param request The request * @param response The response * @param message a message to display * @param smClient internationalized strings * @throws IOException an IO error occurred */
protected void list(HttpServletRequest request, HttpServletResponse response, String message, StringManager smClient) throws IOException { if (debug >= 1) log("list: Listing contexts for virtual host '" + host.getName() + "'"); PrintWriter writer = response.getWriter(); Object[] args = new Object[2]; args[0] = request.getContextPath(); args[1] = smClient.getString("htmlManagerServlet.title"); // HTML Header Section writer.print(MessageFormat.format( Constants.HTML_HEADER_SECTION, args )); // Body Header Section writer.print(MessageFormat.format (Constants.BODY_HEADER_SECTION, args)); // Message Section args = new Object[3]; args[0] = smClient.getString("htmlManagerServlet.messageLabel"); if (message == null || message.length() == 0) { args[1] = "OK"; } else { args[1] = Escape.htmlElementContent(message); } writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args)); // Manager Section args = new Object[9]; args[0] = smClient.getString("htmlManagerServlet.manager"); args[1] = response.encodeURL(request.getContextPath() + "/html/list"); args[2] = smClient.getString("htmlManagerServlet.list"); args[3] = // External link (request.getContextPath() + "/" + smClient.getString("htmlManagerServlet.helpHtmlManagerFile")); args[4] = smClient.getString("htmlManagerServlet.helpHtmlManager"); args[5] = // External link (request.getContextPath() + "/" + smClient.getString("htmlManagerServlet.helpManagerFile")); args[6] = smClient.getString("htmlManagerServlet.helpManager"); args[7] = response.encodeURL (request.getContextPath() + "/status"); args[8] = smClient.getString("statusServlet.title"); writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args)); // Apps Header Section args = new Object[7]; args[0] = smClient.getString("htmlManagerServlet.appsTitle"); args[1] = smClient.getString("htmlManagerServlet.appsPath"); args[2] = smClient.getString("htmlManagerServlet.appsVersion"); args[3] = smClient.getString("htmlManagerServlet.appsName"); args[4] = smClient.getString("htmlManagerServlet.appsAvailable"); args[5] = smClient.getString("htmlManagerServlet.appsSessions"); args[6] = smClient.getString("htmlManagerServlet.appsTasks"); writer.print(MessageFormat.format(APPS_HEADER_SECTION, args)); // Apps Row Section // Create sorted map of deployed applications by context name. Container children[] = host.findChildren(); String contextNames[] = new String[children.length]; for (int i = 0; i < children.length; i++) contextNames[i] = children[i].getName(); Arrays.sort(contextNames); String appsStart = smClient.getString("htmlManagerServlet.appsStart"); String appsStop = smClient.getString("htmlManagerServlet.appsStop"); String appsReload = smClient.getString("htmlManagerServlet.appsReload"); String appsUndeploy = smClient.getString("htmlManagerServlet.appsUndeploy"); String appsExpire = smClient.getString("htmlManagerServlet.appsExpire"); String noVersion = "<i>" + smClient.getString("htmlManagerServlet.noVersion") + "</i>"; boolean isHighlighted = true; boolean isDeployed = true; String highlightColor = null; for (String contextName : contextNames) { Context ctxt = (Context) host.findChild(contextName); if (ctxt != null) { // Bugzilla 34818, alternating row colors isHighlighted = !isHighlighted; if(isHighlighted) { highlightColor = "#C3F3C3"; } else { highlightColor = "#FFFFFF"; } String contextPath = ctxt.getPath(); String displayPath = contextPath; if (displayPath.equals("")) { displayPath = "/"; } StringBuilder tmp = new StringBuilder(); tmp.append("path="); tmp.append(URLEncoder.DEFAULT.encode(displayPath, StandardCharsets.UTF_8)); final String webappVersion = ctxt.getWebappVersion(); if (webappVersion != null && webappVersion.length() > 0) { tmp.append("&version="); tmp.append(URLEncoder.DEFAULT.encode( webappVersion, StandardCharsets.UTF_8)); } String pathVersion = tmp.toString(); try { isDeployed = isDeployed(contextName); } catch (Exception e) { // Assume false on failure for safety isDeployed = false; } args = new Object[7]; args[0] = // External link "<a href=\"" + URLEncoder.DEFAULT.encode(contextPath + "/", StandardCharsets.UTF_8) + "\" " + Constants.REL_EXTERNAL + ">" + Escape.htmlElementContent(displayPath) + "</a>"; if (webappVersion == null || webappVersion.isEmpty()) { args[1] = noVersion; } else { args[1] = Escape.htmlElementContent(webappVersion); } if (ctxt.getDisplayName() == null) { args[2] = "&nbsp;"; } else { args[2] = Escape.htmlElementContent(ctxt.getDisplayName()); } args[3] = Boolean.valueOf(ctxt.getState().isAvailable()); args[4] = Escape.htmlElementContent(response.encodeURL(request.getContextPath() + "/html/sessions?" + pathVersion)); Manager manager = ctxt.getManager(); if (manager instanceof DistributedManager && showProxySessions) { args[5] = Integer.valueOf( ((DistributedManager)manager).getActiveSessionsFull()); } else if (manager != null){ args[5] = Integer.valueOf(manager.getActiveSessions()); } else { args[5] = Integer.valueOf(0); } args[6] = highlightColor; writer.print (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args)); args = new Object[14]; args[0] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/start?" + pathVersion)); args[1] = appsStart; args[2] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/stop?" + pathVersion)); args[3] = appsStop; args[4] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/reload?" + pathVersion)); args[5] = appsReload; args[6] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/undeploy?" + pathVersion)); args[7] = appsUndeploy; args[8] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/expire?" + pathVersion)); args[9] = appsExpire; args[10] = smClient.getString("htmlManagerServlet.expire.explain"); if (manager == null) { args[11] = smClient.getString("htmlManagerServlet.noManager"); } else { args[11] = Integer.valueOf(ctxt.getSessionTimeout()); } args[12] = smClient.getString("htmlManagerServlet.expire.unit"); args[13] = highlightColor; if (ctxt.getName().equals(this.context.getName())) { writer.print(MessageFormat.format( MANAGER_APP_ROW_BUTTON_SECTION, args)); } else if (ctxt.getState().isAvailable() && isDeployed) { writer.print(MessageFormat.format( STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else if (ctxt.getState().isAvailable() && !isDeployed) { writer.print(MessageFormat.format( STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else if (!ctxt.getState().isAvailable() && isDeployed) { writer.print(MessageFormat.format( STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } else { writer.print(MessageFormat.format( STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION, args)); } } } // Deploy Section args = new Object[8]; args[0] = smClient.getString("htmlManagerServlet.deployTitle"); args[1] = smClient.getString("htmlManagerServlet.deployServer"); args[2] = response.encodeURL(request.getContextPath() + "/html/deploy"); args[3] = smClient.getString("htmlManagerServlet.deployPath"); args[4] = smClient.getString("htmlManagerServlet.deployVersion"); args[5] = smClient.getString("htmlManagerServlet.deployConfig"); args[6] = smClient.getString("htmlManagerServlet.deployWar"); args[7] = smClient.getString("htmlManagerServlet.deployButton"); writer.print(MessageFormat.format(DEPLOY_SECTION, args)); args = new Object[4]; args[0] = smClient.getString("htmlManagerServlet.deployUpload"); args[1] = response.encodeURL(request.getContextPath() + "/html/upload"); args[2] = smClient.getString("htmlManagerServlet.deployUploadFile"); args[3] = smClient.getString("htmlManagerServlet.deployButton"); writer.print(MessageFormat.format(UPLOAD_SECTION, args)); // Config section args = new Object[5]; args[0] = smClient.getString("htmlManagerServlet.configTitle"); args[1] = smClient.getString("htmlManagerServlet.configSslReloadTitle"); args[2] = response.encodeURL(request.getContextPath() + "/html/sslReload"); args[3] = smClient.getString("htmlManagerServlet.configSslHostName"); args[4] = smClient.getString("htmlManagerServlet.configReloadButton"); writer.print(MessageFormat.format(CONFIG_SECTION, args)); // Diagnostics section args = new Object[15]; args[0] = smClient.getString("htmlManagerServlet.diagnosticsTitle"); args[1] = smClient.getString("htmlManagerServlet.diagnosticsLeak"); args[2] = response.encodeURL( request.getContextPath() + "/html/findleaks"); args[3] = smClient.getString("htmlManagerServlet.diagnosticsLeakWarning"); args[4] = smClient.getString("htmlManagerServlet.diagnosticsLeakButton"); args[5] = smClient.getString("htmlManagerServlet.diagnosticsSsl"); args[6] = response.encodeURL( request.getContextPath() + "/html/sslConnectorCiphers"); args[7] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCipherButton"); args[8] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCipherText"); args[9] = response.encodeURL( request.getContextPath() + "/html/sslConnectorCerts"); args[10] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCertsButton"); args[11] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorCertsText"); args[12] = response.encodeURL( request.getContextPath() + "/html/sslConnectorTrustedCerts"); args[13] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorTrustedCertsButton"); args[14] = smClient.getString("htmlManagerServlet.diagnosticsSslConnectorTrustedCertsText"); writer.print(MessageFormat.format(DIAGNOSTICS_SECTION, args)); // Server Header Section args = new Object[9]; args[0] = smClient.getString("htmlManagerServlet.serverTitle"); args[1] = smClient.getString("htmlManagerServlet.serverVersion"); args[2] = smClient.getString("htmlManagerServlet.serverJVMVersion"); args[3] = smClient.getString("htmlManagerServlet.serverJVMVendor"); args[4] = smClient.getString("htmlManagerServlet.serverOSName"); args[5] = smClient.getString("htmlManagerServlet.serverOSVersion"); args[6] = smClient.getString("htmlManagerServlet.serverOSArch"); args[7] = smClient.getString("htmlManagerServlet.serverHostname"); args[8] = smClient.getString("htmlManagerServlet.serverIPAddress"); writer.print(MessageFormat.format (Constants.SERVER_HEADER_SECTION, args)); // Server Row Section args = new Object[8]; args[0] = ServerInfo.getServerInfo(); args[1] = System.getProperty("java.runtime.version"); args[2] = System.getProperty("java.vm.vendor"); args[3] = System.getProperty("os.name"); args[4] = System.getProperty("os.version"); args[5] = System.getProperty("os.arch"); try { InetAddress address = InetAddress.getLocalHost(); args[6] = address.getHostName(); args[7] = address.getHostAddress(); } catch (UnknownHostException e) { args[6] = "-"; args[7] = "-"; } writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args)); // HTML Tail Section writer.print(Constants.HTML_TAIL_SECTION); // Finish up the response writer.flush(); writer.close(); }
Reload the web application at the specified context path.
Params:
  • cn – Name of the application to be restarted
  • smClient – StringManager for the client's locale
See Also:
  • reload.reload(PrintWriter, ContextName, StringManager)
Returns:message String
/** * Reload the web application at the specified context path. * * @see ManagerServlet#reload(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be restarted * @param smClient StringManager for the client's locale * @return message String */
protected String reload(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.reload(printWriter, cn, smClient); return stringWriter.toString(); }
Undeploy the web application at the specified context path.
Params:
  • cn – Name of the application to be undeployed
  • smClient – StringManager for the client's locale
See Also:
  • undeploy.undeploy(PrintWriter, ContextName, StringManager)
Returns:message String
/** * Undeploy the web application at the specified context path. * * @see ManagerServlet#undeploy(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be undeployed * @param smClient StringManager for the client's locale * @return message String */
protected String undeploy(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.undeploy(printWriter, cn, smClient); return stringWriter.toString(); }
Display session information and invoke list.
Params:
  • cn – Name of the application to list session information
  • idle – Expire all sessions with idle time ≥ idle for this context
  • smClient – StringManager for the client's locale
See Also:
  • sessions.sessions(PrintWriter, ContextName, int, StringManager)
Returns:message String
/** * Display session information and invoke list. * * @see ManagerServlet#sessions(PrintWriter, ContextName, int, * StringManager) * * @param cn Name of the application to list session information * @param idle Expire all sessions with idle time &ge; idle for this context * @param smClient StringManager for the client's locale * @return message String */
protected String sessions(ContextName cn, int idle, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.sessions(printWriter, cn, idle, smClient); return stringWriter.toString(); }
Start the web application at the specified context path.
Params:
  • cn – Name of the application to be started
  • smClient – StringManager for the client's locale
See Also:
  • start.start(PrintWriter, ContextName, StringManager)
Returns:message String
/** * Start the web application at the specified context path. * * @see ManagerServlet#start(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be started * @param smClient StringManager for the client's locale * @return message String */
protected String start(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.start(printWriter, cn, smClient); return stringWriter.toString(); }
Stop the web application at the specified context path.
Params:
  • cn – Name of the application to be stopped
  • smClient – StringManager for the client's locale
See Also:
  • stop.stop(PrintWriter, ContextName, StringManager)
Returns:message String
/** * Stop the web application at the specified context path. * * @see ManagerServlet#stop(PrintWriter, ContextName, StringManager) * * @param cn Name of the application to be stopped * @param smClient StringManager for the client's locale * @return message String */
protected String stop(ContextName cn, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.stop(printWriter, cn, smClient); return stringWriter.toString(); }
Find potential memory leaks caused by web application reload.
Params:
  • smClient – StringManager for the client's locale
See Also:
  • findleaks.findleaks(boolean, PrintWriter, StringManager)
Returns:message String
/** * Find potential memory leaks caused by web application reload. * * @see ManagerServlet#findleaks(boolean, PrintWriter, StringManager) * * @param smClient StringManager for the client's locale * * @return message String */
protected String findleaks(StringManager smClient) { StringBuilder msg = new StringBuilder(); StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.findleaks(false, printWriter, smClient); String writerText = stringWriter.toString(); if (writerText.length() > 0) { if (!writerText.startsWith("FAIL -")) { msg.append(smClient.getString( "htmlManagerServlet.findleaksList")); } msg.append(writerText); } else { msg.append(smClient.getString("htmlManagerServlet.findleaksNone")); } return msg.toString(); } protected String sslReload(String tlsHostName, StringManager smClient) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); super.sslReload(printWriter, tlsHostName, smClient); return stringWriter.toString(); } protected void sslConnectorCiphers(HttpServletRequest request, HttpServletResponse response, StringManager smClient) throws ServletException, IOException { request.setAttribute("cipherList", getConnectorCiphers(smClient)); getServletContext().getRequestDispatcher( connectorCiphersJspPath).forward(request, response); } protected void sslConnectorCerts(HttpServletRequest request, HttpServletResponse response, StringManager smClient) throws ServletException, IOException { request.setAttribute("certList", getConnectorCerts(smClient)); getServletContext().getRequestDispatcher( connectorCertsJspPath).forward(request, response); } protected void sslConnectorTrustedCerts(HttpServletRequest request, HttpServletResponse response, StringManager smClient) throws ServletException, IOException { request.setAttribute("trustedCertList", getConnectorTrustedCerts(smClient)); getServletContext().getRequestDispatcher( connectorTrustedCertsJspPath).forward(request, response); }
See Also:
  • getServletInfo.getServletInfo()
/** * @see jakarta.servlet.Servlet#getServletInfo() */
@Override public String getServletInfo() { return "HTMLManagerServlet, Copyright (c) 1999-2020, The Apache Software Foundation"; }
See Also:
  • init.init()
/** * @see jakarta.servlet.GenericServlet#init() */
@Override public void init() throws ServletException { super.init(); // Set our properties from the initialization parameters String value = null; value = getServletConfig().getInitParameter("showProxySessions"); showProxySessions = Boolean.parseBoolean(value); } // ------------------------------------------------ Sessions administration
Extract the expiration request parameter
Params:
  • cn – Name of the application from which to expire sessions
  • req – The Servlet request
  • smClient – StringManager for the client's locale
Returns:message string
/** * * Extract the expiration request parameter * * @param cn Name of the application from which to expire sessions * @param req The Servlet request * @param smClient StringManager for the client's locale * @return message string */
protected String expireSessions(ContextName cn, HttpServletRequest req, StringManager smClient) { int idle = -1; String idleParam = req.getParameter("idle"); if (idleParam != null) { try { idle = Integer.parseInt(idleParam); } catch (NumberFormatException e) { log(sm.getString("managerServlet.error.idleParam", idleParam)); } } return sessions(cn, idle, smClient); }
Handle session operations.
Params:
  • cn – Name of the application for the sessions operation
  • req – The Servlet request
  • resp – The Servlet response
  • smClient – StringManager for the client's locale
Throws:
/** * Handle session operations. * * @param cn Name of the application for the sessions operation * @param req The Servlet request * @param resp The Servlet response * @param smClient StringManager for the client's locale * @throws ServletException Propagated Servlet error * @throws IOException An IO error occurred */
protected void doSessions(ContextName cn, HttpServletRequest req, HttpServletResponse resp, StringManager smClient) throws ServletException, IOException { req.setAttribute("path", cn.getPath()); req.setAttribute("version", cn.getVersion()); String action = req.getParameter("action"); if (debug >= 1) { log("sessions: Session action '" + action + "' for web application '" + cn.getDisplayName() + "'"); } if ("sessionDetail".equals(action)) { String sessionId = req.getParameter("sessionId"); displaySessionDetailPage(req, resp, cn, sessionId, smClient); return; } else if ("invalidateSessions".equals(action)) { String[] sessionIds = req.getParameterValues("sessionIds"); int i = invalidateSessions(cn, sessionIds, smClient); req.setAttribute(APPLICATION_MESSAGE, "" + i + " sessions invalidated."); } else if ("removeSessionAttribute".equals(action)) { String sessionId = req.getParameter("sessionId"); String name = req.getParameter("attributeName"); boolean removed = removeSessionAttribute(cn, sessionId, name, smClient); String outMessage = removed ? "Session attribute '" + name + "' removed." : "Session did not contain any attribute named '" + name + "'"; req.setAttribute(APPLICATION_MESSAGE, outMessage); displaySessionDetailPage(req, resp, cn, sessionId, smClient); return; } // else displaySessionsListPage(cn, req, resp, smClient); } protected List<Session> getSessionsForName(ContextName cn, StringManager smClient) { if ((cn == null) || !(cn.getPath().startsWith("/") || cn.getPath().equals(""))) { String path = null; if (cn != null) { path = cn.getPath(); } throw new IllegalArgumentException(smClient.getString( "managerServlet.invalidPath", Escape.htmlElementContent(path))); } Context ctxt = (Context) host.findChild(cn.getName()); if (null == ctxt) { throw new IllegalArgumentException(smClient.getString( "managerServlet.noContext", Escape.htmlElementContent(cn.getDisplayName()))); } Manager manager = ctxt.getManager(); List<Session> sessions = new ArrayList<>(Arrays.asList(manager.findSessions())); if (manager instanceof DistributedManager && showProxySessions) { // Add dummy proxy sessions Set<String> sessionIds = ((DistributedManager) manager).getSessionIdsFull(); // Remove active (primary and backup) session IDs from full list for (Session session : sessions) { sessionIds.remove(session.getId()); } // Left with just proxy sessions - add them for (String sessionId : sessionIds) { sessions.add(new DummyProxySession(sessionId)); } } return sessions; } protected Session getSessionForNameAndId(ContextName cn, String id, StringManager smClient) { List<Session> sessions = getSessionsForName(cn, smClient); if (sessions.isEmpty()) return null; for(Session session : sessions) { if (session.getId().equals(id)) { return session; } } return null; }
List session.
Params:
  • cn – Name of the application for which the sessions will be listed
  • req – The Servlet request
  • resp – The Servlet response
  • smClient – StringManager for the client's locale
Throws:
/** * List session. * @param cn Name of the application for which the sessions will be listed * @param req The Servlet request * @param resp The Servlet response * @param smClient StringManager for the client's locale * @throws ServletException Propagated Servlet error * @throws IOException An IO error occurred */
protected void displaySessionsListPage(ContextName cn, HttpServletRequest req, HttpServletResponse resp, StringManager smClient) throws ServletException, IOException { List<Session> sessions = getSessionsForName(cn, smClient); String sortBy = req.getParameter("sort"); String orderBy = null; if (null != sortBy && !"".equals(sortBy.trim())) { Comparator<Session> comparator = getComparator(sortBy); if (comparator != null) { orderBy = req.getParameter("order"); if ("DESC".equalsIgnoreCase(orderBy)) { comparator = Collections.reverseOrder(comparator); orderBy = "ASC"; } else { orderBy = "DESC"; } try { sessions.sort(comparator); } catch (IllegalStateException ise) { // at least 1 of the sessions is invalidated req.setAttribute(APPLICATION_ERROR, "Can't sort session list: one session is invalidated"); } } else { log(sm.getString("htmlManagerServlet.error.sortOrder", sortBy)); } } // keep sort order req.setAttribute("sort", sortBy); req.setAttribute("order", orderBy); req.setAttribute("activeSessions", sessions); //strong>NOTE</strong> - This header will be overridden // automatically if a <code>RequestDispatcher.forward()</code> call is // ultimately invoked. resp.setHeader("Pragma", "No-cache"); // HTTP 1.0 resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1 resp.setDateHeader("Expires", 0); // 0 means now getServletContext().getRequestDispatcher(sessionsListJspPath).include(req, resp); }
Display session details.
Params:
  • req – The Servlet request
  • resp – The Servlet response
  • cn – Name of the application for which the sessions will be listed
  • sessionId – the session id
  • smClient – StringManager for the client's locale
Throws:
/** * Display session details. * * @param req The Servlet request * @param resp The Servlet response * @param cn Name of the application for which the sessions will be listed * @param sessionId the session id * @param smClient StringManager for the client's locale * @throws ServletException Propagated Servlet error * @throws IOException An IO error occurred */
protected void displaySessionDetailPage(HttpServletRequest req, HttpServletResponse resp, ContextName cn, String sessionId, StringManager smClient) throws ServletException, IOException { Session session = getSessionForNameAndId(cn, sessionId, smClient); //strong>NOTE</strong> - This header will be overridden // automatically if a <code>RequestDispatcher.forward()</code> call is // ultimately invoked. resp.setHeader("Pragma", "No-cache"); // HTTP 1.0 resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1 resp.setDateHeader("Expires", 0); // 0 means now req.setAttribute("currentSession", session); getServletContext().getRequestDispatcher(resp.encodeURL(sessionDetailJspPath)).include(req, resp); }
Invalidate specified sessions.
Params:
  • cn – Name of the application for which sessions are to be invalidated
  • sessionIds – the session ids of the sessions
  • smClient – StringManager for the client's locale
Returns:number of invalidated sessions
/** * Invalidate specified sessions. * * @param cn Name of the application for which sessions are to be * invalidated * @param sessionIds the session ids of the sessions * @param smClient StringManager for the client's locale * @return number of invalidated sessions */
protected int invalidateSessions(ContextName cn, String[] sessionIds, StringManager smClient) { if (null == sessionIds) { return 0; } int nbAffectedSessions = 0; for (String sessionId : sessionIds) { HttpSession session = getSessionForNameAndId(cn, sessionId, smClient).getSession(); if (null == session) { // Shouldn't happen, but let's play nice... if (debug >= 1) { log("Cannot invalidate null session " + sessionId); } continue; } try { session.invalidate(); ++nbAffectedSessions; if (debug >= 1) { log("Invalidating session id " + sessionId); } } catch (IllegalStateException ise) { if (debug >= 1) { log("Cannot invalidate already invalidated session id " + sessionId); } } } return nbAffectedSessions; }
Removes an attribute from an HttpSession
Params:
  • cn – Name of the application hosting the session from which the attribute is to be removed
  • sessionId – the session id
  • attributeName – the attribute name
  • smClient – StringManager for the client's locale
Returns:true if there was an attribute removed, false otherwise
/** * Removes an attribute from an HttpSession * @param cn Name of the application hosting the session from which the * attribute is to be removed * @param sessionId the session id * @param attributeName the attribute name * @param smClient StringManager for the client's locale * @return true if there was an attribute removed, false otherwise */
protected boolean removeSessionAttribute(ContextName cn, String sessionId, String attributeName, StringManager smClient) { HttpSession session = getSessionForNameAndId(cn, sessionId, smClient).getSession(); if (null == session) { // Shouldn't happen, but let's play nice... if (debug >= 1) { log("Cannot remove attribute '" + attributeName + "' for null session " + sessionId); } return false; } boolean wasPresent = (null != session.getAttribute(attributeName)); try { session.removeAttribute(attributeName); } catch (IllegalStateException ise) { if (debug >= 1) { log("Cannot remote attribute '" + attributeName + "' for invalidated session id " + sessionId); } } return wasPresent; } protected Comparator<Session> getComparator(String sortBy) { Comparator<Session> comparator = null; if ("CreationTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Date>() { @Override public Comparable<Date> getComparableObject(Session session) { return new Date(session.getCreationTime()); } }; } else if ("id".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<String>() { @Override public Comparable<String> getComparableObject(Session session) { return session.getId(); } }; } else if ("LastAccessedTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Date>() { @Override public Comparable<Date> getComparableObject(Session session) { return new Date(session.getLastAccessedTime()); } }; } else if ("MaxInactiveInterval".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Integer>() { @Override public Comparable<Integer> getComparableObject(Session session) { return Integer.valueOf(session.getMaxInactiveInterval()); } }; } else if ("new".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Boolean>() { @Override public Comparable<Boolean> getComparableObject(Session session) { return Boolean.valueOf(session.getSession().isNew()); } }; } else if ("locale".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<String>() { @Override public Comparable<String> getComparableObject(Session session) { return JspHelper.guessDisplayLocaleFromSession(session); } }; } else if ("user".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<String>() { @Override public Comparable<String> getComparableObject(Session session) { return JspHelper.guessDisplayUserFromSession(session); } }; } else if ("UsedTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Date>() { @Override public Comparable<Date> getComparableObject(Session session) { return new Date(SessionUtils.getUsedTimeForSession(session)); } }; } else if ("InactiveTime".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Date>() { @Override public Comparable<Date> getComparableObject(Session session) { return new Date(SessionUtils.getInactiveTimeForSession(session)); } }; } else if ("TTL".equalsIgnoreCase(sortBy)) { comparator = new BaseSessionComparator<Date>() { @Override public Comparable<Date> getComparableObject(Session session) { return new Date(SessionUtils.getTTLForSession(session)); } }; } return comparator; } // ------------------------------------------------------ Private Constants // These HTML sections are broken in relatively small sections, because of // limited number of substitutions MessageFormat can process // (maximum of 10). private static final String APPS_HEADER_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td colspan=\"6\" class=\"title\">{0}</td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"header-left\"><small>{1}</small></td>\n" + " <td class=\"header-left\"><small>{2}</small></td>\n" + " <td class=\"header-center\"><small>{3}</small></td>\n" + " <td class=\"header-center\"><small>{4}</small></td>\n" + " <td class=\"header-left\"><small>{5}</small></td>\n" + " <td class=\"header-left\"><small>{6}</small></td>\n" + "</tr>\n"; private static final String APPS_ROW_DETAILS_SECTION = "<tr>\n" + " <td class=\"row-left\" bgcolor=\"{6}\" rowspan=\"2\"><small>{0}</small></td>\n" + " <td class=\"row-left\" bgcolor=\"{6}\" rowspan=\"2\"><small>{1}</small></td>\n" + " <td class=\"row-left\" bgcolor=\"{6}\" rowspan=\"2\"><small>{2}</small></td>\n" + " <td class=\"row-center\" bgcolor=\"{6}\" rowspan=\"2\"><small>{3}</small></td>\n" + " <td class=\"row-center\" bgcolor=\"{6}\" rowspan=\"2\">" + "<small><a href=\"{4}\">{5}</a></small></td>\n"; private static final String MANAGER_APP_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " <small>\n" + " &nbsp;{1}&nbsp;\n" + " &nbsp;{3}&nbsp;\n" + " &nbsp;{5}&nbsp;\n" + " &nbsp;{7}&nbsp;\n" + " </small>\n" + " </td>\n" + "</tr><tr>\n" + " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " <form method=\"POST\" action=\"{8}\">\n" + " <small>\n" + " &nbsp;<input type=\"submit\" value=\"{9}\">&nbsp;{10}&nbsp;<input type=\"text\" name=\"idle\" size=\"5\" value=\"{11}\">&nbsp;{12}&nbsp;\n" + " </small>\n" + " </form>\n" + " </td>\n" + "</tr>\n"; private static final String STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " &nbsp;<small>{1}</small>&nbsp;\n" + " <form class=\"inline\" method=\"POST\" action=\"{2}\">" + " <small><input type=\"submit\" value=\"{3}\"></small>" + " </form>\n" + " <form class=\"inline\" method=\"POST\" action=\"{4}\">" + " <small><input type=\"submit\" value=\"{5}\"></small>" + " </form>\n" + " <form class=\"inline\" method=\"POST\" action=\"{6}\">" + " &nbsp;&nbsp;<small><input type=\"submit\" value=\"{7}\"></small>" + " </form>\n" + " </td>\n" + " </tr><tr>\n" + " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " <form method=\"POST\" action=\"{8}\">\n" + " <small>\n" + " &nbsp;<input type=\"submit\" value=\"{9}\">&nbsp;{10}&nbsp;<input type=\"text\" name=\"idle\" size=\"5\" value=\"{11}\">&nbsp;{12}&nbsp;\n" + " </small>\n" + " </form>\n" + " </td>\n" + "</tr>\n"; private static final String STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n" + " <form class=\"inline\" method=\"POST\" action=\"{0}\">" + " <small><input type=\"submit\" value=\"{1}\"></small>" + " </form>\n" + " &nbsp;<small>{3}</small>&nbsp;\n" + " &nbsp;<small>{5}</small>&nbsp;\n" + " <form class=\"inline\" method=\"POST\" action=\"{6}\">" + " <small><input type=\"submit\" value=\"{7}\"></small>" + " </form>\n" + " </td>\n" + "</tr>\n<tr></tr>\n"; private static final String STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " &nbsp;<small>{1}</small>&nbsp;\n" + " <form class=\"inline\" method=\"POST\" action=\"{2}\">" + " <small><input type=\"submit\" value=\"{3}\"></small>" + " </form>\n" + " <form class=\"inline\" method=\"POST\" action=\"{4}\">" + " <small><input type=\"submit\" value=\"{5}\"></small>" + " </form>\n" + " &nbsp;<small>{7}</small>&nbsp;\n" + " </td>\n" + " </tr><tr>\n" + " <td class=\"row-left\" bgcolor=\"{13}\">\n" + " <form method=\"POST\" action=\"{8}\">\n" + " <small>\n" + " &nbsp;<input type=\"submit\" value=\"{9}\">&nbsp;{10}&nbsp;<input type=\"text\" name=\"idle\" size=\"5\" value=\"{11}\">&nbsp;{12}&nbsp;\n" + " </small>\n" + " </form>\n" + " </td>\n" + "</tr>\n"; private static final String STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n" + " <form class=\"inline\" method=\"POST\" action=\"{0}\">" + " <small><input type=\"submit\" value=\"{1}\"></small>" + " </form>\n" + " &nbsp;<small>{3}</small>&nbsp;\n" + " &nbsp;<small>{5}</small>&nbsp;\n" + " &nbsp;<small>{7}</small>&nbsp;\n" + " </td>\n" + "</tr>\n<tr></tr>\n"; private static final String DEPLOY_SECTION = "</table>\n" + "<br>\n" + "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td colspan=\"2\" class=\"title\">{0}</td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\">\n" + "<form method=\"post\" action=\"{2}\">\n" + "<table cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{3}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"text\" name=\"deployPath\" size=\"20\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{4}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"text\" name=\"deployVersion\" size=\"20\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{5}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"text\" name=\"deployConfig\" size=\"20\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{6}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"text\" name=\"deployWar\" size=\"40\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " &nbsp;\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"submit\" value=\"{7}\">\n" + " </td>\n" + "</tr>\n" + "</table>\n" + "</form>\n" + "</td>\n" + "</tr>\n"; private static final String UPLOAD_SECTION = "<tr>\n" + " <td colspan=\"2\" class=\"header-left\"><small>{0}</small></td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\">\n" + "<form method=\"post\" action=\"{1}\" " + "enctype=\"multipart/form-data\">\n" + "<table cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{2}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"file\" name=\"deployWar\" size=\"40\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " &nbsp;\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"submit\" value=\"{3}\">\n" + " </td>\n" + "</tr>\n" + "</table>\n" + "</form>\n" + "</td>\n" + "</tr>\n" + "</table>\n" + "<br>\n" + "\n"; private static final String CONFIG_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td colspan=\"2\" class=\"title\">{0}</td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\">\n" + "<form method=\"post\" action=\"{2}\">\n" + "<table cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " <small>{3}</small>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"text\" name=\"tlsHostName\" size=\"20\">\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-right\">\n" + " &nbsp;\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <input type=\"submit\" value=\"{4}\">\n" + " </td>\n" + "</tr>\n" + "</table>\n" + "</form>\n" + "</td>\n" + "</tr>\n" + "</table>\n" + "<br>"; private static final String DIAGNOSTICS_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" + "<tr>\n" + " <td colspan=\"2\" class=\"title\">{0}</td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-left\">\n" + " <form method=\"post\" action=\"{2}\">\n" + " <input type=\"submit\" value=\"{4}\">\n" + " </form>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <small>{3}</small>\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td colspan=\"2\" class=\"header-left\"><small>{5}</small></td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-left\">\n" + " <form method=\"post\" action=\"{6}\">\n" + " <input type=\"submit\" value=\"{7}\">\n" + " </form>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <small>{8}</small>\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-left\">\n" + " <form method=\"post\" action=\"{9}\">\n" + " <input type=\"submit\" value=\"{10}\">\n" + " </form>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <small>{11}</small>\n" + " </td>\n" + "</tr>\n" + "<tr>\n" + " <td class=\"row-left\">\n" + " <form method=\"post\" action=\"{12}\">\n" + " <input type=\"submit\" value=\"{13}\">\n" + " </form>\n" + " </td>\n" + " <td class=\"row-left\">\n" + " <small>{14}</small>\n" + " </td>\n" + "</tr>\n" + "</table>\n" + "<br>"; }