/*
* 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.PrintWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.security.Escape;
/**
* This is a refactoring of the servlet to externalize
* the output into a simple class. Although we could
* use XSLT, that is unnecessarily complex.
*
* @author Peter Lin
*/
public class StatusTransformer {
// --------------------------------------------------------- Public Methods
public static void setContentType(HttpServletResponse response,
int mode) {
if (mode == 0){
response.setContentType("text/html;charset="+Constants.CHARSET);
} else if (mode == 1){
response.setContentType("text/xml;charset="+Constants.CHARSET);
}
}
/**
* Write an HTML or XML header.
*
* @param writer the PrintWriter to use
* @param args Path prefix for URLs
* @param mode - 0 = HTML header, 1 = XML declaration
*
*/
public static void writeHeader(PrintWriter writer, Object[] args, int mode) {
if (mode == 0){
// HTML Header Section
writer.print(Constants.HTML_HEADER_SECTION);
} else if (mode == 1){
writer.write(Constants.XML_DECLARATION);
writer.print(MessageFormat.format
(Constants.XML_STYLE, args));
writer.write("0 will generate HTML.
* Mode 1 will generate XML.
* @param args I18n labels for the OS state values
*/
public static void writeOSState(PrintWriter writer, int mode, Object[] args) {
long[] result = new long[16];
boolean ok = false;
try {
String methodName = "info";
Class> paramTypes[] = new Class[1];
paramTypes[0] = result.getClass();
Object paramValues[] = new Object[1];
paramValues[0] = result;
Method method = Class.forName("org.apache.tomcat.jni.OS")
.getMethod(methodName, paramTypes);
method.invoke(null, paramValues);
ok = true;
} catch (Throwable t) {
t = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(t);
}
if (ok) {
if (mode == 0){
writer.print("
");
writer.print( args[0] );
writer.print(' ');
writer.print(formatSize(Long.valueOf(result[0]), true));
writer.print(' ');
writer.print(args[1]);
writer.print(' ');
writer.print(formatSize(Long.valueOf(result[1]), true));
writer.print(' ');
writer.print(args[2]);
writer.print(' ');
writer.print(formatSize(Long.valueOf(result[2]), true));
writer.print(' ');
writer.print(args[3]);
writer.print(' ');
writer.print(formatSize(Long.valueOf(result[3]), true));
writer.print(' ');
writer.print(args[4]);
writer.print(' ');
writer.print(Long.valueOf(result[6]));
writer.print("
");
writer.print(args[5]);
writer.print(' ');
writer.print(formatTime(Long.valueOf(result[11] / 1000), true));
writer.print(' ');
writer.print(args[6]);
writer.print(' ');
writer.print(formatTime(Long.valueOf(result[12] / 1000), true));
writer.print("
0 will generate HTML.
* Mode 1 will generate XML.
* @param args I18n labels for the VM state values
* @throws Exception Propagated JMX error
*/
public static void writeVMState(PrintWriter writer, int mode, Object[] args)
throws Exception {
SortedMap"); writer.print( args[0] ); writer.print(' '); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().freeMemory()), true)); writer.print(' '); writer.print(args[1]); writer.print(' '); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().totalMemory()), true)); writer.print(' '); writer.print(args[2]); writer.print(' '); writer.print(formatSize( Long.valueOf(Runtime.getRuntime().maxMemory()), true)); writer.print("
"); writer.write("| " + args[3] + " | " + args[4] + " | " + args[5] + " | " + args[6] + " | " + args[7] + " | " + args[8] + " |
|---|---|---|---|---|---|
| "); writer.print(memoryPoolMBean.getName()); writer.write(" | "); writer.print(memoryPoolMBean.getType()); writer.write(" | "); writer.print(formatSize(Long.valueOf(usage.getInit()), true)); writer.write(" | "); writer.print(formatSize(Long.valueOf(usage.getCommitted()), true)); writer.write(" | "); writer.print(formatSize(Long.valueOf(usage.getMax()), true)); writer.write(" | "); writer.print(formatSize(Long.valueOf(usage.getUsed()), true)); if (usage.getMax() > 0) { writer.write(" (" + (usage.getUsed() * 100 / usage.getMax()) + "%)"); } writer.write(" |
0 will generate HTML.
* Mode 1 will generate XML.
* @param args I18n labels for the Connector state values
* @throws Exception Propagated JMX error
*/
public static void writeConnectorState(PrintWriter writer,
ObjectName tpName, String name, MBeanServer mBeanServer,
Vector");
writer.print( args[0] );
writer.print(' ');
writer.print(mBeanServer.getAttribute(tpName, "maxThreads"));
writer.print(' ');
writer.print(args[1]);
writer.print(' ');
writer.print(mBeanServer.getAttribute(tpName, "currentThreadCount"));
writer.print(' ');
writer.print(args[2]);
writer.print(' ');
writer.print(mBeanServer.getAttribute(tpName, "currentThreadsBusy"));
writer.print(' ');
writer.print(args[3]);
writer.print(' ');
writer.print(mBeanServer.getAttribute(tpName, "keepAliveCount"));
writer.print("
");
ObjectName grpName = null;
Enumeration
| "+ args[10] + " | " + args[11] + " | " + args[12] +" | " + args[13] +" | " + args[14] + " | " + args[15] + " | " + args[16] + " | " + args[17] + " |
|---|---|---|---|---|---|---|---|
"); writer.print( args[18] ); writer.print("
"); } else if (mode == 1){ writer.write("0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
protected static void writeProcessorState(PrintWriter writer,
ObjectName pName,
MBeanServer mBeanServer,
int mode)
throws Exception {
Integer stageValue =
(Integer) mBeanServer.getAttribute(pName, "stage");
int stage = stageValue.intValue();
boolean fullStatus = true;
boolean showRequest = true;
String stageStr = null;
switch (stage) {
case (1/*org.apache.coyote.Constants.STAGE_PARSE*/):
stageStr = "P";
fullStatus = false;
break;
case (2/*org.apache.coyote.Constants.STAGE_PREPARE*/):
stageStr = "P";
fullStatus = false;
break;
case (3/*org.apache.coyote.Constants.STAGE_SERVICE*/):
stageStr = "S";
break;
case (4/*org.apache.coyote.Constants.STAGE_ENDINPUT*/):
stageStr = "F";
break;
case (5/*org.apache.coyote.Constants.STAGE_ENDOUTPUT*/):
stageStr = "F";
break;
case (7/*org.apache.coyote.Constants.STAGE_ENDED*/):
stageStr = "R";
fullStatus = false;
break;
case (6/*org.apache.coyote.Constants.STAGE_KEEPALIVE*/):
stageStr = "K";
fullStatus = true;
showRequest = false;
break;
case (0/*org.apache.coyote.Constants.STAGE_NEW*/):
stageStr = "R";
fullStatus = false;
break;
default:
// Unknown stage
stageStr = "?";
fullStatus = false;
}
if (mode == 0) {
writer.write("0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
public static void writeDetailedState(PrintWriter writer,
MBeanServer mBeanServer, int mode)
throws Exception {
if (mode == 0){
ObjectName queryHosts = new ObjectName("*:j2eeType=WebModule,*");
Set");
int count = 0;
Iterator
");
}
}
writer.print("
0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
protected static void writeContext(PrintWriter writer,
ObjectName objectName,
MBeanServer mBeanServer, int mode)
throws Exception {
if (mode == 0){
String webModuleName = objectName.getKeyProperty("name");
String name = webModuleName;
if (name == null) {
return;
}
String hostName = null;
String contextName = null;
if (name.startsWith("//")) {
name = name.substring(2);
}
int slash = name.indexOf('/');
if (slash != -1) {
hostName = name.substring(0, slash);
contextName = name.substring(slash);
} else {
return;
}
ObjectName queryManager = new ObjectName
(objectName.getDomain() + ":type=Manager,context=" + contextName
+ ",host=" + hostName + ",*");
Set"); Object startTime = mBeanServer.getAttribute(objectName, "startTime"); writer.print(" Start time: " + new Date(((Long) startTime).longValue())); writer.print(" Startup time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "startupTime"), false)); writer.print(" TLD scan time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "tldScanTime"), false)); if (managerON != null) { writeManager(writer, managerON, mBeanServer, mode); } if (jspMonitorONs != null) { writeJspMonitor(writer, jspMonitorONs, mBeanServer, mode); } writer.print("
"); String onStr = objectName.getDomain() + ":j2eeType=Servlet,WebModule=" + webModuleName + ",*"; ObjectName servletObjectName = new ObjectName(onStr); Set0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
public static void writeManager(PrintWriter writer, ObjectName objectName,
MBeanServer mBeanServer, int mode)
throws Exception {
if (mode == 0) {
writer.print("0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
public static void writeJspMonitor(PrintWriter writer,
Set0 will generate HTML.
* Mode 1 will generate XML.
* @throws Exception Propagated JMX error
*/
public static void writeWrapper(PrintWriter writer, ObjectName objectName,
MBeanServer mBeanServer, int mode)
throws Exception {
if (mode == 0) {
String servletName = objectName.getKeyProperty("name");
String[] mappings = (String[])
mBeanServer.invoke(objectName, "findMappings", null, null);
writer.print(""); writer.print(" Processing time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "processingTime"), true)); writer.print(" Max time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "maxTime"), false)); writer.print(" Request count: "); writer.print(mBeanServer.getAttribute(objectName, "requestCount")); writer.print(" Error count: "); writer.print(mBeanServer.getAttribute(objectName, "errorCount")); writer.print(" Load time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "loadTime"), false)); writer.print(" Classloading time: "); writer.print(formatTime(mBeanServer.getAttribute (objectName, "classLoadTime"), false)); writer.print("
"); } else if (mode == 1){ // for now we don't write out the wrapper details } } /** * Filter the specified message string for characters that are sensitive * in HTML. This avoids potential attacks caused by including JavaScript * codes in the request URL that is often reported in error messages. * * @param obj The message string to be filtered * @return filtered HTML content * * @deprecated This method will be removed in Tomcat 9 */ @Deprecated public static String filter(Object obj) { if (obj == null) return ("?"); String message = obj.toString(); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return result.toString(); } /** * Escape the 5 entities defined by XML. * @param s The message string to be filtered * @return filtered XML content * * @deprecated This method will be removed in Tomcat 9 */ @Deprecated public static String filterXml(String s) { if (s == null) return ""; StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '<') { sb.append("<"); } else if (c == '>') { sb.append(">"); } else if (c == '\'') { sb.append("'"); } else if (c == '&') { sb.append("&"); } else if (c == '"') { sb.append("""); } else { sb.append(c); } } return sb.toString(); } /** * Display the given size in bytes, either as KB or MB. * * @param obj The object to format * @param mb true to display megabytes, false for kilobytes * @return formatted size */ public static String formatSize(Object obj, boolean mb) { long bytes = -1L; if (obj instanceof Long) { bytes = ((Long) obj).longValue(); } else if (obj instanceof Integer) { bytes = ((Integer) obj).intValue(); } if (mb) { StringBuilder buff = new StringBuilder(); if (bytes < 0) { buff.append('-'); bytes = -bytes; } long mbytes = bytes / (1024 * 1024); long rest = ((bytes - (mbytes * (1024 * 1024))) * 100) / (1024 * 1024); buff.append(mbytes).append('.'); if (rest < 10) { buff.append('0'); } buff.append(rest).append(" MB"); return buff.toString(); } else { return ((bytes / 1024) + " KB"); } } /** * Display the given time in ms, either as ms or s. * * @param obj The object to format * @param seconds true to display seconds, false for milliseconds * @return formatted time */ public static String formatTime(Object obj, boolean seconds) { long time = -1L; if (obj instanceof Long) { time = ((Long) obj).longValue(); } else if (obj instanceof Integer) { time = ((Integer) obj).intValue(); } if (seconds) { return ((((float) time ) / 1000) + " s"); } else { return (time + " ms"); } } /** * Formats the given time (given in seconds) as a string. * * @param obj Time object to be formatted as string * @return formatted time */ public static String formatSeconds(Object obj) { long time = -1L; if (obj instanceof Long) { time = ((Long) obj).longValue(); } else if (obj instanceof Integer) { time = ((Integer) obj).intValue(); } return (time + " s"); } }