0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.catalina.manager;
0019:
0020: import java.io.File;
0021: import java.io.IOException;
0022: import java.io.PrintWriter;
0023: import java.io.StringWriter;
0024: import java.text.MessageFormat;
0025: import java.util.Arrays;
0026: import java.util.Collections;
0027: import java.util.Comparator;
0028: import java.util.Date;
0029: import java.util.Iterator;
0030: import java.util.List;
0031: import java.util.Map;
0032: import java.util.TreeMap;
0033: import javax.servlet.ServletException;
0034: import javax.servlet.http.HttpServletRequest;
0035: import javax.servlet.http.HttpServletResponse;
0036: import javax.servlet.http.HttpSession;
0037:
0038: import org.apache.catalina.Container;
0039: import org.apache.catalina.Context;
0040: import org.apache.catalina.Session;
0041: import org.apache.catalina.manager.util.BaseSessionComparator;
0042: import org.apache.catalina.manager.util.ReverseComparator;
0043: import org.apache.catalina.manager.util.SessionUtils;
0044: import org.apache.catalina.util.RequestUtil;
0045: import org.apache.catalina.util.ServerInfo;
0046: import org.apache.tomcat.util.http.fileupload.DiskFileUpload;
0047: import org.apache.tomcat.util.http.fileupload.FileItem;
0048:
0049: /**
0050: * Servlet that enables remote management of the web applications deployed
0051: * within the same virtual host as this web application is. Normally, this
0052: * functionality will be protected by a security constraint in the web
0053: * application deployment descriptor. However, this requirement can be
0054: * relaxed during testing.
0055: * <p>
0056: * The difference between the <code>ManagerServlet</code> and this
0057: * Servlet is that this Servlet prints out a HTML interface which
0058: * makes it easier to administrate.
0059: * <p>
0060: * However if you use a software that parses the output of
0061: * <code>ManagerServlet</code> you won't be able to upgrade
0062: * to this Servlet since the output are not in the
0063: * same format ar from <code>ManagerServlet</code>
0064: *
0065: * @author Bip Thelin
0066: * @author Malcolm Edgar
0067: * @author Glenn L. Nielsen
0068: * @version $Revision: 547077 $, $Date: 2007-06-14 03:55:09 +0200 (jeu., 14 juin 2007) $
0069: * @see ManagerServlet
0070: */
0071:
0072: public final class HTMLManagerServlet extends ManagerServlet {
0073:
0074: protected static final String APPLICATION_MESSAGE = "message";
0075: protected static final String APPLICATION_ERROR = "error";
0076: protected String sessionsListJspPath = "/sessionsList.jsp";
0077: protected String sessionDetailJspPath = "/sessionDetail.jsp";
0078:
0079: // --------------------------------------------------------- Public Methods
0080:
0081: /**
0082: * Process a GET request for the specified resource.
0083: *
0084: * @param request The servlet request we are processing
0085: * @param response The servlet response we are creating
0086: *
0087: * @exception IOException if an input/output error occurs
0088: * @exception ServletException if a servlet-specified error occurs
0089: */
0090: public void doGet(HttpServletRequest request,
0091: HttpServletResponse response) throws IOException,
0092: ServletException {
0093:
0094: // Identify the request parameters that we need
0095: String command = request.getPathInfo();
0096:
0097: String path = request.getParameter("path");
0098: String deployPath = request.getParameter("deployPath");
0099: String deployConfig = request.getParameter("deployConfig");
0100: String deployWar = request.getParameter("deployWar");
0101:
0102: // Prepare our output writer to generate the response message
0103: response.setContentType("text/html; charset="
0104: + Constants.CHARSET);
0105:
0106: String message = "";
0107: // Process the requested command
0108: if (command == null || command.equals("/")) {
0109: } else if (command.equals("/deploy")) {
0110: message = deployInternal(deployConfig, deployPath,
0111: deployWar);
0112: } else if (command.equals("/list")) {
0113: } else if (command.equals("/reload")) {
0114: message = reload(path);
0115: } else if (command.equals("/undeploy")) {
0116: message = undeploy(path);
0117: } else if (command.equals("/expire")) {
0118: message = expireSessions(path, request);
0119: } else if (command.equals("/sessions")) {
0120: try {
0121: doSessions(path, request, response);
0122: return;
0123: } catch (Exception e) {
0124: log("HTMLManagerServlet.sessions[" + path + "]", e);
0125: message = sm.getString("managerServlet.exception", e
0126: .toString());
0127: }
0128: } else if (command.equals("/start")) {
0129: message = start(path);
0130: } else if (command.equals("/stop")) {
0131: message = stop(path);
0132: } else {
0133: message = sm.getString("managerServlet.unknownCommand",
0134: command);
0135: }
0136:
0137: list(request, response, message);
0138: }
0139:
0140: /**
0141: * Process a POST request for the specified resource.
0142: *
0143: * @param request The servlet request we are processing
0144: * @param response The servlet response we are creating
0145: *
0146: * @exception IOException if an input/output error occurs
0147: * @exception ServletException if a servlet-specified error occurs
0148: */
0149: public void doPost(HttpServletRequest request,
0150: HttpServletResponse response) throws IOException,
0151: ServletException {
0152:
0153: // Identify the request parameters that we need
0154: String command = request.getPathInfo();
0155:
0156: if (command == null || !command.equals("/upload")) {
0157: doGet(request, response);
0158: return;
0159: }
0160:
0161: // Prepare our output writer to generate the response message
0162: response.setContentType("text/html; charset="
0163: + Constants.CHARSET);
0164:
0165: String message = "";
0166:
0167: // Create a new file upload handler
0168: DiskFileUpload upload = new DiskFileUpload();
0169:
0170: // Get the tempdir
0171: File tempdir = (File) getServletContext().getAttribute(
0172: "javax.servlet.context.tempdir");
0173: // Set upload parameters
0174: upload.setSizeMax(-1);
0175: upload.setRepositoryPath(tempdir.getCanonicalPath());
0176:
0177: // Parse the request
0178: String basename = null;
0179: String war = null;
0180: FileItem warUpload = null;
0181: try {
0182: List items = upload.parseRequest(request);
0183:
0184: // Process the uploaded fields
0185: Iterator iter = items.iterator();
0186: while (iter.hasNext()) {
0187: FileItem item = (FileItem) iter.next();
0188:
0189: if (!item.isFormField()) {
0190: if (item.getFieldName().equals("deployWar")
0191: && warUpload == null) {
0192: warUpload = item;
0193: } else {
0194: item.delete();
0195: }
0196: }
0197: }
0198: while (true) {
0199: if (warUpload == null) {
0200: message = sm
0201: .getString("htmlManagerServlet.deployUploadNoFile");
0202: break;
0203: }
0204: war = warUpload.getName();
0205: if (!war.toLowerCase().endsWith(".war")) {
0206: message = sm.getString(
0207: "htmlManagerServlet.deployUploadNotWar",
0208: war);
0209: break;
0210: }
0211: // Get the filename if uploaded name includes a path
0212: if (war.lastIndexOf('\\') >= 0) {
0213: war = war.substring(war.lastIndexOf('\\') + 1);
0214: }
0215: if (war.lastIndexOf('/') >= 0) {
0216: war = war.substring(war.lastIndexOf('/') + 1);
0217: }
0218: // Identify the appBase of the owning Host of this Context
0219: // (if any)
0220: basename = war.substring(0, war.toLowerCase().indexOf(
0221: ".war"));
0222: File file = new File(getAppBase(), war);
0223: if (file.exists()) {
0224: message = sm.getString(
0225: "htmlManagerServlet.deployUploadWarExists",
0226: war);
0227: break;
0228: }
0229: String path = null;
0230: if (basename.equals("ROOT")) {
0231: path = "";
0232: } else {
0233: path = "/" + basename;
0234: }
0235:
0236: if (!isServiced(path)) {
0237: addServiced(path);
0238: try {
0239: warUpload.write(file);
0240: // Perform new deployment
0241: check(path);
0242: } finally {
0243: removeServiced(path);
0244: }
0245: }
0246: break;
0247: }
0248: } catch (Exception e) {
0249: message = sm.getString(
0250: "htmlManagerServlet.deployUploadFail", e
0251: .getMessage());
0252: log(message, e);
0253: } finally {
0254: if (warUpload != null) {
0255: warUpload.delete();
0256: }
0257: warUpload = null;
0258: }
0259:
0260: list(request, response, message);
0261: }
0262:
0263: /**
0264: * Deploy an application for the specified path from the specified
0265: * web application archive.
0266: *
0267: * @param config URL of the context configuration file to be deployed
0268: * @param path Context path of the application to be deployed
0269: * @param war URL of the web application archive to be deployed
0270: * @return message String
0271: */
0272: protected String deployInternal(String config, String path,
0273: String war) {
0274:
0275: StringWriter stringWriter = new StringWriter();
0276: PrintWriter printWriter = new PrintWriter(stringWriter);
0277:
0278: super .deploy(printWriter, config, path, war, false);
0279:
0280: return stringWriter.toString();
0281: }
0282:
0283: /**
0284: * Render a HTML list of the currently active Contexts in our virtual host,
0285: * and memory and server status information.
0286: *
0287: * @param request The request
0288: * @param response The response
0289: * @param message a message to display
0290: */
0291: public void list(HttpServletRequest request,
0292: HttpServletResponse response, String message)
0293: throws IOException {
0294:
0295: if (debug >= 1)
0296: log("list: Listing contexts for virtual host '"
0297: + host.getName() + "'");
0298:
0299: PrintWriter writer = response.getWriter();
0300:
0301: // HTML Header Section
0302: writer.print(Constants.HTML_HEADER_SECTION);
0303:
0304: // Body Header Section
0305: Object[] args = new Object[2];
0306: args[0] = request.getContextPath();
0307: args[1] = sm.getString("htmlManagerServlet.title");
0308: writer.print(MessageFormat.format(
0309: Constants.BODY_HEADER_SECTION, args));
0310:
0311: // Message Section
0312: args = new Object[3];
0313: args[0] = sm.getString("htmlManagerServlet.messageLabel");
0314: if (message == null || message.length() == 0) {
0315: args[1] = "OK";
0316: } else {
0317: args[1] = RequestUtil.filter(message);
0318: }
0319: writer.print(MessageFormat.format(Constants.MESSAGE_SECTION,
0320: args));
0321:
0322: // Manager Section
0323: args = new Object[9];
0324: args[0] = sm.getString("htmlManagerServlet.manager");
0325: args[1] = response.encodeURL(request.getContextPath()
0326: + "/html/list");
0327: args[2] = sm.getString("htmlManagerServlet.list");
0328: args[3] = response
0329: .encodeURL(request.getContextPath()
0330: + "/"
0331: + sm
0332: .getString("htmlManagerServlet.helpHtmlManagerFile"));
0333: args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
0334: args[5] = response.encodeURL(request.getContextPath() + "/"
0335: + sm.getString("htmlManagerServlet.helpManagerFile"));
0336: args[6] = sm.getString("htmlManagerServlet.helpManager");
0337: args[7] = response.encodeURL(request.getContextPath()
0338: + "/status");
0339: args[8] = sm.getString("statusServlet.title");
0340: writer.print(MessageFormat.format(Constants.MANAGER_SECTION,
0341: args));
0342:
0343: // Apps Header Section
0344: args = new Object[6];
0345: args[0] = sm.getString("htmlManagerServlet.appsTitle");
0346: args[1] = sm.getString("htmlManagerServlet.appsPath");
0347: args[2] = sm.getString("htmlManagerServlet.appsName");
0348: args[3] = sm.getString("htmlManagerServlet.appsAvailable");
0349: args[4] = sm.getString("htmlManagerServlet.appsSessions");
0350: args[5] = sm.getString("htmlManagerServlet.appsTasks");
0351: writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
0352:
0353: // Apps Row Section
0354: // Create sorted map of deployed applications context paths.
0355: Container children[] = host.findChildren();
0356: String contextPaths[] = new String[children.length];
0357: for (int i = 0; i < children.length; i++)
0358: contextPaths[i] = children[i].getName();
0359:
0360: TreeMap sortedContextPathsMap = new TreeMap();
0361:
0362: for (int i = 0; i < contextPaths.length; i++) {
0363: String displayPath = contextPaths[i];
0364: sortedContextPathsMap.put(displayPath, contextPaths[i]);
0365: }
0366:
0367: String appsStart = sm.getString("htmlManagerServlet.appsStart");
0368: String appsStop = sm.getString("htmlManagerServlet.appsStop");
0369: String appsReload = sm
0370: .getString("htmlManagerServlet.appsReload");
0371: String appsUndeploy = sm
0372: .getString("htmlManagerServlet.appsUndeploy");
0373: String appsExpire = sm
0374: .getString("htmlManagerServlet.appsExpire");
0375:
0376: Iterator iterator = sortedContextPathsMap.entrySet().iterator();
0377: boolean isHighlighted = true;
0378: boolean isDeployed = true;
0379: String highlightColor = null;
0380:
0381: while (iterator.hasNext()) {
0382: // Bugzilla 34818, alternating row colors
0383: isHighlighted = !isHighlighted;
0384: if (isHighlighted) {
0385: highlightColor = "#C3F3C3";
0386: } else {
0387: highlightColor = "#FFFFFF";
0388: }
0389:
0390: Map.Entry entry = (Map.Entry) iterator.next();
0391: String displayPath = (String) entry.getKey();
0392: String contextPath = (String) entry.getKey();
0393: Context context = (Context) host.findChild(contextPath);
0394: if (displayPath.equals("")) {
0395: displayPath = "/";
0396: }
0397:
0398: if (context != null) {
0399: try {
0400: isDeployed = isDeployed(contextPath);
0401: } catch (Exception e) {
0402: // Assume false on failure for safety
0403: isDeployed = false;
0404: }
0405:
0406: args = new Object[6];
0407: args[0] = displayPath;
0408: args[1] = context.getDisplayName();
0409: if (args[1] == null) {
0410: args[1] = " ";
0411: }
0412: args[2] = new Boolean(context.getAvailable());
0413: args[3] = response.encodeURL(request.getContextPath()
0414: + "/html/sessions?path=" + displayPath);
0415: if (context.getManager() != null) {
0416: args[4] = new Integer(context.getManager()
0417: .getActiveSessions());
0418: } else {
0419: args[4] = new Integer(0);
0420: }
0421:
0422: args[5] = highlightColor;
0423:
0424: writer.print(MessageFormat.format(
0425: APPS_ROW_DETAILS_SECTION, args));
0426:
0427: args = new Object[14];
0428: args[0] = response.encodeURL(request.getContextPath()
0429: + "/html/start?path=" + displayPath);
0430: args[1] = appsStart;
0431: args[2] = response.encodeURL(request.getContextPath()
0432: + "/html/stop?path=" + displayPath);
0433: args[3] = appsStop;
0434: args[4] = response.encodeURL(request.getContextPath()
0435: + "/html/reload?path=" + displayPath);
0436: args[5] = appsReload;
0437: args[6] = response.encodeURL(request.getContextPath()
0438: + "/html/undeploy?path=" + displayPath);
0439: args[7] = appsUndeploy;
0440:
0441: args[8] = response.encodeURL(request.getContextPath()
0442: + "/html/expire?path=" + displayPath);
0443: args[9] = appsExpire;
0444: args[10] = sm
0445: .getString("htmlManagerServlet.expire.explain");
0446: args[11] = new Integer(context.getManager()
0447: .getMaxInactiveInterval() / 60);
0448: args[12] = sm
0449: .getString("htmlManagerServlet.expire.unit");
0450:
0451: args[13] = highlightColor;
0452:
0453: if (context.getPath().equals(this .context.getPath())) {
0454: writer.print(MessageFormat.format(
0455: MANAGER_APP_ROW_BUTTON_SECTION, args));
0456: } else if (context.getAvailable() && isDeployed) {
0457: writer.print(MessageFormat.format(
0458: STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION,
0459: args));
0460: } else if (context.getAvailable() && !isDeployed) {
0461: writer
0462: .print(MessageFormat
0463: .format(
0464: STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION,
0465: args));
0466: } else if (!context.getAvailable() && isDeployed) {
0467: writer.print(MessageFormat.format(
0468: STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION,
0469: args));
0470: } else {
0471: writer
0472: .print(MessageFormat
0473: .format(
0474: STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION,
0475: args));
0476: }
0477:
0478: }
0479: }
0480:
0481: // Deploy Section
0482: args = new Object[7];
0483: args[0] = sm.getString("htmlManagerServlet.deployTitle");
0484: args[1] = sm.getString("htmlManagerServlet.deployServer");
0485: args[2] = response.encodeURL(request.getContextPath()
0486: + "/html/deploy");
0487: args[3] = sm.getString("htmlManagerServlet.deployPath");
0488: args[4] = sm.getString("htmlManagerServlet.deployConfig");
0489: args[5] = sm.getString("htmlManagerServlet.deployWar");
0490: args[6] = sm.getString("htmlManagerServlet.deployButton");
0491: writer.print(MessageFormat.format(DEPLOY_SECTION, args));
0492:
0493: args = new Object[4];
0494: args[0] = sm.getString("htmlManagerServlet.deployUpload");
0495: args[1] = response.encodeURL(request.getContextPath()
0496: + "/html/upload");
0497: args[2] = sm.getString("htmlManagerServlet.deployUploadFile");
0498: args[3] = sm.getString("htmlManagerServlet.deployButton");
0499: writer.print(MessageFormat.format(UPLOAD_SECTION, args));
0500:
0501: // Server Header Section
0502: args = new Object[7];
0503: args[0] = sm.getString("htmlManagerServlet.serverTitle");
0504: args[1] = sm.getString("htmlManagerServlet.serverVersion");
0505: args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
0506: args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
0507: args[4] = sm.getString("htmlManagerServlet.serverOSName");
0508: args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
0509: args[6] = sm.getString("htmlManagerServlet.serverOSArch");
0510: writer.print(MessageFormat.format(
0511: Constants.SERVER_HEADER_SECTION, args));
0512:
0513: // Server Row Section
0514: args = new Object[6];
0515: args[0] = ServerInfo.getServerInfo();
0516: args[1] = System.getProperty("java.runtime.version");
0517: args[2] = System.getProperty("java.vm.vendor");
0518: args[3] = System.getProperty("os.name");
0519: args[4] = System.getProperty("os.version");
0520: args[5] = System.getProperty("os.arch");
0521: writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION,
0522: args));
0523:
0524: // HTML Tail Section
0525: writer.print(Constants.HTML_TAIL_SECTION);
0526:
0527: // Finish up the response
0528: writer.flush();
0529: writer.close();
0530: }
0531:
0532: /**
0533: * Reload the web application at the specified context path.
0534: *
0535: * @see ManagerServlet#reload(PrintWriter, String)
0536: *
0537: * @param path Context path of the application to be restarted
0538: * @return message String
0539: */
0540: protected String reload(String path) {
0541:
0542: StringWriter stringWriter = new StringWriter();
0543: PrintWriter printWriter = new PrintWriter(stringWriter);
0544:
0545: super .reload(printWriter, path);
0546:
0547: return stringWriter.toString();
0548: }
0549:
0550: /**
0551: * Undeploy the web application at the specified context path.
0552: *
0553: * @see ManagerServlet#undeploy(PrintWriter, String)
0554: *
0555: * @param path Context path of the application to be undeployd
0556: * @return message String
0557: */
0558: protected String undeploy(String path) {
0559:
0560: StringWriter stringWriter = new StringWriter();
0561: PrintWriter printWriter = new PrintWriter(stringWriter);
0562:
0563: super .undeploy(printWriter, path);
0564:
0565: return stringWriter.toString();
0566: }
0567:
0568: /**
0569: * Display session information and invoke list.
0570: *
0571: * @see ManagerServlet#sessions(PrintWriter, String, int)
0572: *
0573: * @param path Context path of the application to list session information
0574: * @param idle Expire all sessions with idle time ≥ idle for this context
0575: * @return message String
0576: */
0577: public String sessions(String path, int idle) {
0578:
0579: StringWriter stringWriter = new StringWriter();
0580: PrintWriter printWriter = new PrintWriter(stringWriter);
0581:
0582: super .sessions(printWriter, path, idle);
0583:
0584: return stringWriter.toString();
0585: }
0586:
0587: /**
0588: * Display session information and invoke list.
0589: *
0590: * @see ManagerServlet#sessions(PrintWriter, String)
0591: *
0592: * @param path Context path of the application to list session information
0593: * @return message String
0594: */
0595: public String sessions(String path) {
0596:
0597: return sessions(path, -1);
0598: }
0599:
0600: /**
0601: * Start the web application at the specified context path.
0602: *
0603: * @see ManagerServlet#start(PrintWriter, String)
0604: *
0605: * @param path Context path of the application to be started
0606: * @return message String
0607: */
0608: public String start(String path) {
0609:
0610: StringWriter stringWriter = new StringWriter();
0611: PrintWriter printWriter = new PrintWriter(stringWriter);
0612:
0613: super .start(printWriter, path);
0614:
0615: return stringWriter.toString();
0616: }
0617:
0618: /**
0619: * Stop the web application at the specified context path.
0620: *
0621: * @see ManagerServlet#stop(PrintWriter, String)
0622: *
0623: * @param path Context path of the application to be stopped
0624: * @return message String
0625: */
0626: protected String stop(String path) {
0627:
0628: StringWriter stringWriter = new StringWriter();
0629: PrintWriter printWriter = new PrintWriter(stringWriter);
0630:
0631: super .stop(printWriter, path);
0632:
0633: return stringWriter.toString();
0634: }
0635:
0636: /**
0637: * @see javax.servlet.Servlet#getServletInfo()
0638: */
0639: public String getServletInfo() {
0640: return "HTMLManagerServlet, Copyright (c) The Apache Software Foundation";
0641: }
0642:
0643: /**
0644: * @see javax.servlet.GenericServlet#init()
0645: */
0646: public void init() throws ServletException {
0647: super .init();
0648: }
0649:
0650: // ------------------------------------------------ Sessions administration
0651:
0652: /**
0653: *
0654: * Extract the expiration request parameter
0655: *
0656: * @param path
0657: * @param req
0658: */
0659: protected String expireSessions(String path, HttpServletRequest req) {
0660: int idle = -1;
0661: String idleParam = req.getParameter("idle");
0662: if (idleParam != null) {
0663: try {
0664: idle = Integer.parseInt(idleParam);
0665: } catch (NumberFormatException e) {
0666: log("Could not parse idle parameter to an int: "
0667: + idleParam);
0668: }
0669: }
0670: return sessions(path, idle);
0671: }
0672:
0673: /**
0674: *
0675: * @param req
0676: * @param resp
0677: * @throws ServletException
0678: * @throws IOException
0679: */
0680: protected void doSessions(String path, HttpServletRequest req,
0681: HttpServletResponse resp) throws ServletException,
0682: IOException {
0683: req.setAttribute("path", path);
0684: String action = req.getParameter("action");
0685: if (debug >= 1) {
0686: log("sessions: Session action '" + action
0687: + "' for web application at '" + path + "'");
0688: }
0689: if ("sessionDetail".equals(action)) {
0690: String sessionId = req.getParameter("sessionId");
0691: displaySessionDetailPage(req, resp, path, sessionId);
0692: return;
0693: } else if ("invalidateSessions".equals(action)) {
0694: String[] sessionIds = req.getParameterValues("sessionIds");
0695: int i = invalidateSessions(path, sessionIds);
0696: req.setAttribute(APPLICATION_MESSAGE, "" + i
0697: + " sessions invalidated.");
0698: } else if ("removeSessionAttribute".equals(action)) {
0699: String sessionId = req.getParameter("sessionId");
0700: String name = req.getParameter("attributeName");
0701: boolean removed = removeSessionAttribute(path, sessionId,
0702: name);
0703: String outMessage = removed ? "Session attribute '" + name
0704: + "' removed."
0705: : "Session did not contain any attribute named '"
0706: + name + "'";
0707: req.setAttribute(APPLICATION_MESSAGE, outMessage);
0708: resp.sendRedirect(resp.encodeRedirectURL(req
0709: .getRequestURL().append("?path=").append(path)
0710: .append("&action=sessionDetail&sessionId=").append(
0711: sessionId).toString()));
0712: return;
0713: } // else
0714: displaySessionsListPage(path, req, resp);
0715: }
0716:
0717: protected Session[] getSessionsForPath(String path) {
0718: if ((path == null)
0719: || (!path.startsWith("/") && path.equals(""))) {
0720: throw new IllegalArgumentException(sm.getString(
0721: "managerServlet.invalidPath", RequestUtil
0722: .filter(path)));
0723: }
0724: String displayPath = path;
0725: if (path.equals("/"))
0726: path = "";
0727: Context context = (Context) host.findChild(path);
0728: if (null == context) {
0729: throw new IllegalArgumentException(sm.getString(
0730: "managerServlet.noContext", RequestUtil
0731: .filter(displayPath)));
0732: }
0733: Session[] sessions = context.getManager().findSessions();
0734: return sessions;
0735: }
0736:
0737: protected Session getSessionForPathAndId(String path, String id)
0738: throws IOException {
0739: if ((path == null)
0740: || (!path.startsWith("/") && path.equals(""))) {
0741: throw new IllegalArgumentException(sm.getString(
0742: "managerServlet.invalidPath", RequestUtil
0743: .filter(path)));
0744: }
0745: String displayPath = path;
0746: if (path.equals("/"))
0747: path = "";
0748: Context context = (Context) host.findChild(path);
0749: if (null == context) {
0750: throw new IllegalArgumentException(sm.getString(
0751: "managerServlet.noContext", RequestUtil
0752: .filter(displayPath)));
0753: }
0754: Session session = context.getManager().findSession(id);
0755: return session;
0756: }
0757:
0758: /**
0759: *
0760: * @param req
0761: * @param resp
0762: * @throws ServletException
0763: * @throws IOException
0764: */
0765: protected void displaySessionsListPage(String path,
0766: HttpServletRequest req, HttpServletResponse resp)
0767: throws ServletException, IOException {
0768: List/*<Session>*/activeSessions = Arrays
0769: .asList(getSessionsForPath(path));
0770: String sortBy = req.getParameter("sort");
0771: String orderBy = null;
0772: if (null != sortBy && !"".equals(sortBy.trim())) {
0773: Comparator comparator = getComparator(sortBy);
0774: if (comparator != null) {
0775: orderBy = req.getParameter("order");
0776: if ("DESC".equalsIgnoreCase(orderBy)) {
0777: comparator = new ReverseComparator(comparator);
0778: // orderBy = "ASC";
0779: } else {
0780: //orderBy = "DESC";
0781: }
0782: try {
0783: Collections.sort(activeSessions, comparator);
0784: } catch (IllegalStateException ise) {
0785: // at least 1 of the sessions is invalidated
0786: req
0787: .setAttribute(APPLICATION_ERROR,
0788: "Can't sort session list: one session is invalidated");
0789: }
0790: } else {
0791: log("WARNING: unknown sort order: " + sortBy);
0792: }
0793: }
0794: // keep sort order
0795: req.setAttribute("sort", sortBy);
0796: req.setAttribute("order", orderBy);
0797: req.setAttribute("activeSessions", activeSessions);
0798: //strong>NOTE</strong> - This header will be overridden
0799: // automatically if a <code>RequestDispatcher.forward()</code> call is
0800: // ultimately invoked.
0801: resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
0802: resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
0803: resp.setDateHeader("Expires", 0); // 0 means now
0804: getServletContext().getRequestDispatcher(sessionsListJspPath)
0805: .include(req, resp);
0806: }
0807:
0808: /**
0809: *
0810: * @param req
0811: * @param resp
0812: * @throws ServletException
0813: * @throws IOException
0814: */
0815: protected void displaySessionDetailPage(HttpServletRequest req,
0816: HttpServletResponse resp, String path, String sessionId)
0817: throws ServletException, IOException {
0818: Session session = getSessionForPathAndId(path, sessionId);
0819: //strong>NOTE</strong> - This header will be overridden
0820: // automatically if a <code>RequestDispatcher.forward()</code> call is
0821: // ultimately invoked.
0822: resp.setHeader("Pragma", "No-cache"); // HTTP 1.0
0823: resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0"); // HTTP 1.1
0824: resp.setDateHeader("Expires", 0); // 0 means now
0825: req.setAttribute("currentSession", session);
0826: getServletContext().getRequestDispatcher(sessionDetailJspPath)
0827: .include(req, resp);
0828: }
0829:
0830: /**
0831: * Invalidate HttpSessions
0832: * @param sessionIds
0833: * @return number of invalidated sessions
0834: * @throws IOException
0835: */
0836: public int invalidateSessions(String path, String[] sessionIds)
0837: throws IOException {
0838: if (null == sessionIds) {
0839: return 0;
0840: }
0841: int nbAffectedSessions = 0;
0842: for (int i = 0; i < sessionIds.length; ++i) {
0843: String sessionId = sessionIds[i];
0844: HttpSession session = getSessionForPathAndId(path,
0845: sessionId).getSession();
0846: if (null == session) {
0847: // Shouldn't happen, but let's play nice...
0848: if (debug >= 1) {
0849: log("WARNING: can't invalidate null session "
0850: + sessionId);
0851: }
0852: continue;
0853: }
0854: try {
0855: session.invalidate();
0856: ++nbAffectedSessions;
0857: if (debug >= 1) {
0858: log("Invalidating session id " + sessionId);
0859: }
0860: } catch (IllegalStateException ise) {
0861: if (debug >= 1) {
0862: log("Can't invalidate already invalidated session id "
0863: + sessionId);
0864: }
0865: }
0866: }
0867: return nbAffectedSessions;
0868: }
0869:
0870: /**
0871: * Removes an attribute from an HttpSession
0872: * @param sessionId
0873: * @param attributeName
0874: * @return true if there was an attribute removed, false otherwise
0875: * @throws IOException
0876: */
0877: public boolean removeSessionAttribute(String path,
0878: String sessionId, String attributeName) throws IOException {
0879: HttpSession session = getSessionForPathAndId(path, sessionId)
0880: .getSession();
0881: if (null == session) {
0882: // Shouldn't happen, but let's play nice...
0883: if (debug >= 1) {
0884: log("WARNING: can't remove attribute '" + attributeName
0885: + "' for null session " + sessionId);
0886: }
0887: return false;
0888: }
0889: boolean wasPresent = (null != session
0890: .getAttribute(attributeName));
0891: try {
0892: session.removeAttribute(attributeName);
0893: } catch (IllegalStateException ise) {
0894: if (debug >= 1) {
0895: log("Can't remote attribute '" + attributeName
0896: + "' for invalidated session id " + sessionId);
0897: }
0898: }
0899: return wasPresent;
0900: }
0901:
0902: /**
0903: * Sets the maximum inactive interval (session timeout) an HttpSession
0904: * @param sessionId
0905: * @param maxInactiveInterval in seconds
0906: * @return old value for maxInactiveInterval
0907: * @throws IOException
0908: */
0909: public int setSessionMaxInactiveInterval(String path,
0910: String sessionId, int maxInactiveInterval)
0911: throws IOException {
0912: HttpSession session = getSessionForPathAndId(path, sessionId)
0913: .getSession();
0914: if (null == session) {
0915: // Shouldn't happen, but let's play nice...
0916: if (debug >= 1) {
0917: log("WARNING: can't set timout for null session "
0918: + sessionId);
0919: }
0920: return 0;
0921: }
0922: try {
0923: int oldMaxInactiveInterval = session
0924: .getMaxInactiveInterval();
0925: session.setMaxInactiveInterval(maxInactiveInterval);
0926: return oldMaxInactiveInterval;
0927: } catch (IllegalStateException ise) {
0928: if (debug >= 1) {
0929: log("Can't set MaxInactiveInterval '"
0930: + maxInactiveInterval
0931: + "' for invalidated session id " + sessionId);
0932: }
0933: return 0;
0934: }
0935: }
0936:
0937: protected Comparator getComparator(String sortBy) {
0938: Comparator comparator = null;
0939: if ("CreationTime".equalsIgnoreCase(sortBy)) {
0940: comparator = new BaseSessionComparator() {
0941: public Comparable getComparableObject(Session session) {
0942: return new Date(session.getCreationTime());
0943: }
0944: };
0945: } else if ("id".equalsIgnoreCase(sortBy)) {
0946: comparator = new BaseSessionComparator() {
0947: public Comparable getComparableObject(Session session) {
0948: return session.getId();
0949: }
0950: };
0951: } else if ("LastAccessedTime".equalsIgnoreCase(sortBy)) {
0952: comparator = new BaseSessionComparator() {
0953: public Comparable getComparableObject(Session session) {
0954: return new Date(session.getLastAccessedTime());
0955: }
0956: };
0957: } else if ("MaxInactiveInterval".equalsIgnoreCase(sortBy)) {
0958: comparator = new BaseSessionComparator() {
0959: public Comparable getComparableObject(Session session) {
0960: return new Date(session.getMaxInactiveInterval());
0961: }
0962: };
0963: } else if ("new".equalsIgnoreCase(sortBy)) {
0964: comparator = new BaseSessionComparator() {
0965: public Comparable getComparableObject(Session session) {
0966: return Boolean
0967: .valueOf(session.getSession().isNew());
0968: }
0969: };
0970: } else if ("locale".equalsIgnoreCase(sortBy)) {
0971: comparator = new BaseSessionComparator() {
0972: public Comparable getComparableObject(Session session) {
0973: return JspHelper
0974: .guessDisplayLocaleFromSession(session);
0975: }
0976: };
0977: } else if ("user".equalsIgnoreCase(sortBy)) {
0978: comparator = new BaseSessionComparator() {
0979: public Comparable getComparableObject(Session session) {
0980: return JspHelper
0981: .guessDisplayUserFromSession(session);
0982: }
0983: };
0984: } else if ("UsedTime".equalsIgnoreCase(sortBy)) {
0985: comparator = new BaseSessionComparator() {
0986: public Comparable getComparableObject(Session session) {
0987: return new Date(SessionUtils
0988: .getUsedTimeForSession(session));
0989: }
0990: };
0991: } else if ("InactiveTime".equalsIgnoreCase(sortBy)) {
0992: comparator = new BaseSessionComparator() {
0993: public Comparable getComparableObject(Session session) {
0994: return new Date(SessionUtils
0995: .getInactiveTimeForSession(session));
0996: }
0997: };
0998: } else if ("TTL".equalsIgnoreCase(sortBy)) {
0999: comparator = new BaseSessionComparator() {
1000: public Comparable getComparableObject(Session session) {
1001: return new Date(SessionUtils
1002: .getTTLForSession(session));
1003: }
1004: };
1005: }
1006: //TODO: complete this to TTL, etc.
1007: return comparator;
1008: }
1009:
1010: // ------------------------------------------------------ Private Constants
1011:
1012: // These HTML sections are broken in relatively small sections, because of
1013: // limited number of subsitutions MessageFormat can process
1014: // (maximium of 10).
1015:
1016: private static final String APPS_HEADER_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n"
1017: + "<tr>\n"
1018: + " <td colspan=\"5\" class=\"title\">{0}</td>\n"
1019: + "</tr>\n"
1020: + "<tr>\n"
1021: + " <td class=\"header-left\"><small>{1}</small></td>\n"
1022: + " <td class=\"header-left\"><small>{2}</small></td>\n"
1023: + " <td class=\"header-center\"><small>{3}</small></td>\n"
1024: + " <td class=\"header-center\"><small>{4}</small></td>\n"
1025: + " <td class=\"header-left\"><small>{5}</small></td>\n"
1026: + "</tr>\n";
1027:
1028: private static final String APPS_ROW_DETAILS_SECTION = "<tr>\n"
1029: + " <td class=\"row-left\" bgcolor=\"{5}\" rowspan=\"2\"><small><a href=\"{0}\">{0}</a>"
1030: + "</small></td>\n"
1031: + " <td class=\"row-left\" bgcolor=\"{5}\" rowspan=\"2\"><small>{1}</small></td>\n"
1032: + " <td class=\"row-center\" bgcolor=\"{5}\" rowspan=\"2\"><small>{2}</small></td>\n"
1033: + " <td class=\"row-center\" bgcolor=\"{5}\" rowspan=\"2\">"
1034: + "<small><a href=\"{3}\" target=\"_new\">{4}</a></small></td>\n";
1035:
1036: private static final String MANAGER_APP_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\">\n"
1037: + " <small>\n"
1038: + " {1} \n"
1039: + " {3} \n"
1040: + " {5} \n"
1041: + " {7} \n"
1042: + " </small>\n"
1043: + " </td>\n"
1044: + "</tr><tr>\n"
1045: + " <td class=\"row-left\" bgcolor=\"{13}\">\n"
1046: + " <form method=\"POST\" action=\"{8}\">\n"
1047: + " <small>\n"
1048: + " <input type=\"submit\" value=\"{9}\"> {10} <input type=\"text\" name=\"expire\" size=\"5\" value=\"{11}\"> {12} \n"
1049: + " </small>\n" + " </form>\n" + " </td>\n" + "</tr>\n";
1050:
1051: private static final String STARTED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\">\n"
1052: + " <small>\n"
1053: + " {1} \n"
1054: + " <a href=\"{2}\" onclick=\"return(confirm('''Are you sure?'''))\">{3}</a> \n"
1055: + " <a href=\"{4}\" onclick=\"return(confirm('''Are you sure?'''))\">{5}</a> \n"
1056: + " <a href=\"{6}\" onclick=\"return(confirm('''Are you sure?'''))\">{7}</a> \n"
1057: + " </small>\n"
1058: + " </td>\n"
1059: + " </tr><tr>\n"
1060: + " <td class=\"row-left\" bgcolor=\"{13}\">\n"
1061: + " <form method=\"POST\" action=\"{8}\">\n"
1062: + " <small>\n"
1063: + " <input type=\"submit\" value=\"{9}\"> {10} <input type=\"text\" name=\"expire\" size=\"5\" value=\"{11}\"> {12} \n"
1064: + " </small>\n" + " </form>\n" + " </td>\n" + "</tr>\n";
1065:
1066: private static final String STOPPED_DEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n"
1067: + " <small>\n"
1068: + " <a href=\"{0}\" onclick=\"return(confirm('''Are you sure?'''))\">{1}</a> \n"
1069: + " {3} \n"
1070: + " {5} \n"
1071: + " <a href=\"{6}\" onclick=\"return(confirm('''Are you sure? This will delete the application.'''))\">{7}</a> \n"
1072: + " </small>\n" + " </td>\n" + "</tr>\n<tr></tr>\n";
1073:
1074: private static final String STARTED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n"
1075: + " <small>\n"
1076: + " {1} \n"
1077: + " <a href=\"{2}\" onclick=\"return(confirm('''Are you sure?'''))\">{3}</a> \n"
1078: + " <a href=\"{4}\" onclick=\"return(confirm('''Are you sure?'''))\">{5}</a> \n"
1079: + " {7} \n"
1080: + " </small>\n"
1081: + " </td>\n"
1082: + "</tr>\n<tr></tr>\n";
1083:
1084: private static final String STOPPED_NONDEPLOYED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\" bgcolor=\"{13}\" rowspan=\"2\">\n"
1085: + " <small>\n"
1086: + " <a href=\"{0}\" onclick=\"return(confirm('''Are you sure?'''))\">{1}</a> \n"
1087: + " {3} \n"
1088: + " {5} \n"
1089: + " {7} \n"
1090: + " </small>\n"
1091: + " </td>\n"
1092: + "</tr>\n<tr></tr>\n";
1093:
1094: private static final String DEPLOY_SECTION = "</table>\n"
1095: + "<br>\n"
1096: + "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n"
1097: + "<tr>\n"
1098: + " <td colspan=\"2\" class=\"title\">{0}</td>\n"
1099: + "</tr>\n"
1100: + "<tr>\n"
1101: + " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n"
1102: + "</tr>\n"
1103: + "<tr>\n"
1104: + " <td colspan=\"2\">\n"
1105: + "<form method=\"get\" action=\"{2}\">\n"
1106: + "<table cellspacing=\"0\" cellpadding=\"3\">\n"
1107: + "<tr>\n"
1108: + " <td class=\"row-right\">\n"
1109: + " <small>{3}</small>\n"
1110: + " </td>\n"
1111: + " <td class=\"row-left\">\n"
1112: + " <input type=\"text\" name=\"deployPath\" size=\"20\">\n"
1113: + " </td>\n"
1114: + "</tr>\n"
1115: + "<tr>\n"
1116: + " <td class=\"row-right\">\n"
1117: + " <small>{4}</small>\n"
1118: + " </td>\n"
1119: + " <td class=\"row-left\">\n"
1120: + " <input type=\"text\" name=\"deployConfig\" size=\"20\">\n"
1121: + " </td>\n"
1122: + "</tr>\n"
1123: + "<tr>\n"
1124: + " <td class=\"row-right\">\n"
1125: + " <small>{5}</small>\n"
1126: + " </td>\n"
1127: + " <td class=\"row-left\">\n"
1128: + " <input type=\"text\" name=\"deployWar\" size=\"40\">\n"
1129: + " </td>\n" + "</tr>\n" + "<tr>\n"
1130: + " <td class=\"row-right\">\n" + " \n" + " </td>\n"
1131: + " <td class=\"row-left\">\n"
1132: + " <input type=\"submit\" value=\"{6}\">\n" + " </td>\n"
1133: + "</tr>\n" + "</table>\n" + "</form>\n" + "</td>\n"
1134: + "</tr>\n";
1135:
1136: private static final String UPLOAD_SECTION = "<tr>\n"
1137: + " <td colspan=\"2\" class=\"header-left\"><small>{0}</small></td>\n"
1138: + "</tr>\n"
1139: + "<tr>\n"
1140: + " <td colspan=\"2\">\n"
1141: + "<form action=\"{1}\" method=\"post\" "
1142: + "enctype=\"multipart/form-data\">\n"
1143: + "<table cellspacing=\"0\" cellpadding=\"3\">\n"
1144: + "<tr>\n"
1145: + " <td class=\"row-right\">\n"
1146: + " <small>{2}</small>\n"
1147: + " </td>\n"
1148: + " <td class=\"row-left\">\n"
1149: + " <input type=\"file\" name=\"deployWar\" size=\"40\">\n"
1150: + " </td>\n" + "</tr>\n" + "<tr>\n"
1151: + " <td class=\"row-right\">\n" + " \n" + " </td>\n"
1152: + " <td class=\"row-left\">\n"
1153: + " <input type=\"submit\" value=\"{3}\">\n" + " </td>\n"
1154: + "</tr>\n" + "</table>\n" + "</form>\n" + "</table>\n"
1155: + "<br>\n" + "\n";
1156:
1157: }
|