001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/HTMLManagerServlet.java,v 1.8 2002/06/13 14:58:01 glenn Exp $
003: * $Revision: 1.8 $
004: * $Date: 2002/06/13 14:58:01 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.servlets;
065:
066: import java.io.IOException;
067: import java.io.PrintWriter;
068: import java.io.StringWriter;
069: import java.text.MessageFormat;
070: import java.util.Date;
071: import java.util.Iterator;
072: import java.util.Map;
073: import java.util.TreeMap;
074: import javax.servlet.ServletException;
075: import javax.servlet.http.HttpServletRequest;
076: import javax.servlet.http.HttpServletResponse;
077: import org.apache.catalina.Context;
078: import org.apache.catalina.util.ServerInfo;
079:
080: /**
081: * Servlet that enables remote management of the web applications installed
082: * within the same virtual host as this web application is. Normally, this
083: * functionality will be protected by a security constraint in the web
084: * application deployment descriptor. However, this requirement can be
085: * relaxed during testing.
086: * <p>
087: * The difference between this <code>ManagerServlet</code> and this
088: * Servlet is that this Servlet prints out a HTML interface which
089: * makes it easier to administrate.
090: * <p>
091: * However if you use a software that parses the output of
092: * <code>ManagerServlet</code you won't be able to upgrade
093: * to this Servlet since the output are not in the
094: * same format ar from <code>ManagerServlet</code>
095: *
096: * @author Bip Thelin
097: * @author Malcolm Edgar
098: * @version $Revision: 1.8 $, $Date: 2002/06/13 14:58:01 $
099: * @see ManagerServlet
100: */
101:
102: public final class HTMLManagerServlet extends ManagerServlet {
103:
104: // --------------------------------------------------------- Public Methods
105:
106: /**
107: * Process a GET request for the specified resource.
108: *
109: * @param request The servlet request we are processing
110: * @param response The servlet response we are creating
111: *
112: * @exception IOException if an input/output error occurs
113: * @exception ServletException if a servlet-specified error occurs
114: */
115: public void doGet(HttpServletRequest request,
116: HttpServletResponse response) throws IOException,
117: ServletException {
118:
119: // Identify the request parameters that we need
120: String command = request.getPathInfo();
121:
122: String path = request.getParameter("path");
123: String installPath = request.getParameter("installPath");
124: String installConfig = request.getParameter("installConfig");
125: String installWar = request.getParameter("installWar");
126:
127: // Prepare our output writer to generate the response message
128: response.setContentType("text/html");
129: PrintWriter writer = response.getWriter();
130:
131: // Process the requested command
132: if (command == null) {
133: response.sendRedirect(request.getRequestURI() + "/list");
134: } else if (command.equals("/install")) {
135: install(writer, installConfig, installPath, installWar);
136: } else if (command.equals("/list")) {
137: list(writer, "");
138: } else if (command.equals("/reload")) {
139: reload(writer, path);
140: } else if (command.equals("/remove")) {
141: remove(writer, path);
142: } else if (command.equals("/sessions")) {
143: sessions(writer, path);
144: } else if (command.equals("/start")) {
145: start(writer, path);
146: } else if (command.equals("/stop")) {
147: stop(writer, path);
148: } else {
149: String message = sm.getString(
150: "managerServlet.unknownCommand", command);
151: list(writer, message);
152: }
153:
154: // Finish up the response
155: writer.flush();
156: writer.close();
157: }
158:
159: /**
160: * Install an application for the specified path from the specified
161: * web application archive.
162: *
163: * @param writer Writer to render results to
164: * @param config URL of the context configuration file to be installed
165: * @param path Context path of the application to be installed
166: * @param war URL of the web application archive to be installed
167: */
168: protected void install(PrintWriter writer, String config,
169: String path, String war) {
170:
171: StringWriter stringWriter = new StringWriter();
172: PrintWriter printWriter = new PrintWriter(stringWriter);
173:
174: super .install(printWriter, config, path, war);
175:
176: list(writer, stringWriter.toString());
177: }
178:
179: /**
180: * Render a HTML list of the currently active Contexts in our virtual host,
181: * and memory and server status information.
182: *
183: * @param writer Writer to render to
184: * @param message a message to display
185: */
186: public void list(PrintWriter writer, String message) {
187:
188: if (debug >= 1)
189: log("list: Listing contexts for virtual host '"
190: + deployer.getName() + "'");
191:
192: // HTML Header Section
193: writer.print(HTML_HEADER_SECTION);
194:
195: // Body Header Section
196: Object[] args = new Object[1];
197: args[0] = sm.getString("htmlManagerServlet.title");
198: writer.print(MessageFormat.format(BODY_HEADER_SECTION, args));
199:
200: // Message Section
201: args = new Object[3];
202: args[0] = sm.getString("htmlManagerServlet.messageLabel");
203: args[1] = (message != null) ? message : "";
204: writer.print(MessageFormat.format(MESSAGE_SECTION, args));
205:
206: // Apps Header Section
207: args = new Object[5];
208: args[0] = sm.getString("htmlManagerServlet.appsTitle");
209: args[1] = sm.getString("htmlManagerServlet.appsPath");
210: args[2] = sm.getString("htmlManagerServlet.appsName");
211: args[3] = sm.getString("htmlManagerServlet.appsAvailable");
212: args[4] = sm.getString("htmlManagerServlet.appsSessions");
213: writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
214:
215: // Apps Row Section
216: // Create sorted map of deployed applications context paths.
217: String contextPaths[] = deployer.findDeployedApps();
218:
219: TreeMap sortedContextPathsMap = new TreeMap();
220:
221: for (int i = 0; i < contextPaths.length; i++) {
222: String displayPath = contextPaths[i];
223: if (displayPath.equals("")) {
224: displayPath = "/";
225: }
226: sortedContextPathsMap.put(displayPath, contextPaths[i]);
227: }
228:
229: String appsStart = sm.getString("htmlManagerServlet.appsStart");
230: String appsStop = sm.getString("htmlManagerServlet.appsStop");
231: String appsReload = sm
232: .getString("htmlManagerServlet.appsReload");
233: String appsRemove = sm
234: .getString("htmlManagerServlet.appsRemove");
235:
236: Iterator iterator = sortedContextPathsMap.entrySet().iterator();
237: while (iterator.hasNext()) {
238: Map.Entry entry = (Map.Entry) iterator.next();
239: String displayPath = (String) entry.getKey();
240: String contextPath = (String) entry.getKey();
241: Context context = deployer.findDeployedApp(contextPath);
242:
243: if (context != null) {
244: args = new Object[6];
245: args[0] = displayPath;
246: args[1] = context.getDisplayName();
247: if (args[1] == null) {
248: args[1] = " ";
249: }
250: args[2] = new Boolean(context.getAvailable());
251: args[3] = new Integer(context.getManager()
252: .findSessions().length);
253: writer.print(MessageFormat.format(
254: APPS_ROW_DETAILS_SECTION, args));
255:
256: args = new Object[5];
257: args[0] = displayPath;
258: args[1] = appsStart;
259: args[2] = appsStop;
260: args[3] = appsReload;
261: args[4] = appsRemove;
262: if (context.getAvailable()) {
263: writer.print(MessageFormat.format(
264: STARTED_APPS_ROW_BUTTON_SECTION, args));
265: } else {
266: writer.print(MessageFormat.format(
267: STOPPED_APPS_ROW_BUTTON_SECTION, args));
268: }
269:
270: } else if (displayPath.equals("/")) {
271: args = new Object[4];
272: args[0] = displayPath;
273: args[1] = "ROOT";
274: args[2] = new Boolean(true);
275: args[3] = "-";
276: writer.print(MessageFormat.format(
277: APPS_ROOT_ROW_SECTION, args));
278: }
279: }
280:
281: // Install Section
282: args = new Object[5];
283: args[0] = sm.getString("htmlManagerServlet.installTitle");
284: args[1] = sm.getString("htmlManagerServlet.installPath");
285: args[2] = sm.getString("htmlManagerServlet.installConfig");
286: args[3] = sm.getString("htmlManagerServlet.installWar");
287: args[4] = sm.getString("htmlManagerServlet.installButton");
288: writer.print(MessageFormat.format(INSTALL_SECTION, args));
289:
290: // Server Header Section
291: args = new Object[7];
292: args[0] = sm.getString("htmlManagerServlet.serverTitle");
293: args[1] = sm.getString("htmlManagerServlet.serverVersion");
294: args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
295: args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
296: args[4] = sm.getString("htmlManagerServlet.serverOSName");
297: args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
298: args[6] = sm.getString("htmlManagerServlet.serverOSArch");
299: writer.print(MessageFormat.format(SERVER_HEADER_SECTION, args));
300:
301: // Server Row Section
302: args = new Object[6];
303: args[0] = ServerInfo.getServerInfo();
304: args[1] = System.getProperty("java.runtime.version");
305: args[2] = System.getProperty("java.vm.vendor");
306: args[3] = System.getProperty("os.name");
307: args[4] = System.getProperty("os.version");
308: args[5] = System.getProperty("os.arch");
309: writer.print(MessageFormat.format(SERVER_ROW_SECTION, args));
310:
311: // HTML Tail Section
312: writer.print(HTML_TAIL_SECTION);
313: }
314:
315: /**
316: * Reload the web application at the specified context path.
317: *
318: * @see ManagerServlet#reload(PrintWriter, String)
319: *
320: * @param writer Writer to render to
321: * @param path Context path of the application to be restarted
322: */
323: protected void reload(PrintWriter writer, String path) {
324:
325: StringWriter stringWriter = new StringWriter();
326: PrintWriter printWriter = new PrintWriter(stringWriter);
327:
328: super .reload(printWriter, path);
329:
330: list(writer, stringWriter.toString());
331: }
332:
333: /**
334: * Remove the web application at the specified context path.
335: *
336: * @see ManagerServlet#remove(PrintWriter, String)
337: *
338: * @param writer Writer to render to
339: * @param path Context path of the application to be removed
340: */
341: protected void remove(PrintWriter writer, String path) {
342:
343: StringWriter stringWriter = new StringWriter();
344: PrintWriter printWriter = new PrintWriter(stringWriter);
345:
346: super .remove(printWriter, path);
347:
348: list(writer, stringWriter.toString());
349: }
350:
351: /**
352: * Display session information and invoke list.
353: *
354: * @see ManagerServlet#sessions(PrintWriter, String)
355: *
356: * @param writer Writer to render to
357: * @param path Context path of the application to list session information for
358: */
359: public void sessions(PrintWriter writer, String path) {
360:
361: StringWriter stringWriter = new StringWriter();
362: PrintWriter printWriter = new PrintWriter(stringWriter);
363:
364: super .sessions(printWriter, path);
365:
366: list(writer, stringWriter.toString());
367: }
368:
369: /**
370: * Start the web application at the specified context path.
371: *
372: * @see ManagerServlet#start(PrintWriter, String)
373: *
374: * @param writer Writer to render to
375: * @param path Context path of the application to be started
376: */
377: public void start(PrintWriter writer, String path) {
378:
379: StringWriter stringWriter = new StringWriter();
380: PrintWriter printWriter = new PrintWriter(stringWriter);
381:
382: super .start(printWriter, path);
383:
384: list(writer, stringWriter.toString());
385: }
386:
387: /**
388: * Stop the web application at the specified context path.
389: *
390: * @see ManagerServlet#stop(PrintWriter, String)
391: *
392: * @param writer Writer to render to
393: * @param path Context path of the application to be stopped
394: */
395: protected void stop(PrintWriter writer, String path) {
396:
397: StringWriter stringWriter = new StringWriter();
398: PrintWriter printWriter = new PrintWriter(stringWriter);
399:
400: super .stop(printWriter, path);
401:
402: list(writer, stringWriter.toString());
403: }
404:
405: // ------------------------------------------------------ Private Constants
406:
407: // These HTML sections are broken in relatively small sections, because of
408: // limited number of subsitutions MessageFormat can process
409: // (maximium of 10).
410:
411: private static final String HTML_HEADER_SECTION = "<html> \n"
412: + "<head> \n" + "<style> \n"
413: + " table { width: 100%; } \n" + " td.page-title { \n"
414: + " text-align: center; \n"
415: + " vertical-align: top; \n"
416: + " font-family:verdana,sans-serif; \n"
417: + " font-weight: bold; \n" + " background: white; \n"
418: + " color: black; \n" + " } \n" + " td.title { \n"
419: + " text-align: left; \n"
420: + " vertical-align: top; \n"
421: + " font-family:verdana,sans-serif; \n"
422: + " font-style:italic; \n" + " font-weight: bold; \n"
423: + " background: #D2A41C; \n" + " } \n"
424: + " td.header-left { \n" + " text-align: left; \n"
425: + " vertical-align: top; \n"
426: + " font-family:verdana,sans-serif; \n"
427: + " font-weight: bold; \n"
428: + " background: #FFDC75; \n" + " } \n"
429: + " td.header-center { \n" + " text-align: center; \n"
430: + " vertical-align: top; \n"
431: + " font-family:verdana,sans-serif; \n"
432: + " font-weight: bold; \n"
433: + " background: #FFDC75; \n" + " } \n"
434: + " td.row-left { \n" + " text-align: left; \n"
435: + " vertical-align: middle; \n"
436: + " font-family:verdana,sans-serif; \n"
437: + " color: black; \n" + " background: white; \n"
438: + " } \n" + " td.row-center { \n"
439: + " text-align: center; \n"
440: + " vertical-align: middle; \n"
441: + " font-family:verdana,sans-serif; \n"
442: + " color: black; \n" + " background: white; \n"
443: + " } \n" + " td.row-right { \n"
444: + " text-align: right; \n"
445: + " vertical-align: middle; \n"
446: + " font-family:verdana,sans-serif; \n"
447: + " color: black; \n" + " background: white; \n"
448: + " } \n" + "</style> \n";
449:
450: private static final String BODY_HEADER_SECTION = "<title>{0}</title> \n"
451: + "</head> \n"
452: + "\n"
453: + "<body bgcolor=\"#FFFFFF\"> \n"
454: + "\n"
455: + "<table border=\"2\" cellspacing=\"0\" cellpadding=\"3\" "
456: + "bordercolor=\"#000000\"> \n"
457: + "<tr> \n"
458: + " <td class=\"page-title\" bordercolor=\"#000000\" align=\"left\" "
459: + "nowrap> \n"
460: + " <font size=\"+2\">{0}</font> \n"
461: + " </td> \n"
462: + "</tr> \n"
463: + "</table> \n"
464: + "<br> \n"
465: + "\n";
466:
467: private static final String MESSAGE_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\"> \n"
468: + " <tr> \n"
469: + " <td class=\"row-left\"><small><b>{0}</b> {1}</small></td>\n"
470: + " </tr> \n" + "</table> \n" + "<br> \n" + "\n";
471:
472: private static final String APPS_HEADER_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\"> \n"
473: + "<tr> \n"
474: + " <td colspan=\"10\" class=\"title\">{0}</td> \n"
475: + "</tr> \n"
476: + "<tr> \n"
477: + " <td class=\"header-left\"><small>{1}</small></td> \n"
478: + " <td class=\"header-left\"><small>{2}</small></td> \n"
479: + " <td class=\"header-center\"><small>{3}</small></td> \n"
480: + " <td class=\"header-center\"><small>{4}</small></td> \n"
481: + " <td class=\"header-center\"> </td> \n"
482: + "</tr> \n";
483:
484: private static final String APPS_ROW_DETAILS_SECTION = "<tr> \n"
485: + " <td class=\"row-left\"><small><a href=\"{0}\">{0}</a>"
486: + "</small></td> \n"
487: + " <td class=\"row-left\"><small>{1}</small></td> \n"
488: + " <td class=\"row-center\"><small>{2}</small></td> \n"
489: + " <td class=\"row-center\">"
490: + "<small><a href=\"sessions?path={0}\">{3}</a></small></td> \n";
491:
492: private static final String STARTED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\"> \n"
493: + " <small> \n"
494: + " {1} \n"
495: + " <a href=\"stop?path={0}\">{2}</a> \n"
496: + " <a href=\"reload?path={0}\">{3}</a> \n"
497: + " <a href=\"remove?path={0}\">{4}</a> \n"
498: + " </small> \n" + " </td> \n" + "</tr> \n";
499:
500: private static final String STOPPED_APPS_ROW_BUTTON_SECTION = " <td class=\"row-left\"> \n"
501: + " <small> \n"
502: + " <a href=\"start?path={0}\">{1}</a> \n"
503: + " {2} \n"
504: + " {3} \n"
505: + " <a href=\"remove?path={0}\">{4}</a> \n"
506: + " </small> \n" + " </td> \n" + "</tr> \n";
507:
508: private static final String APPS_ROOT_ROW_SECTION = "<tr> \n"
509: + " <td class=\"row-left\"><small><a href=\"{0}\">{0}</a></small></td>\n"
510: + " <td class=\"row-left\"><small>{1}</small></td> \n"
511: + " <td class=\"row-center\"><small>{2}</small></td> \n"
512: + " <td class=\"row-center\"><small>{3}</small></td> \n"
513: + " <td class=\"row-right\"> </td> \n" + "</tr> \n";
514:
515: private static final String INSTALL_SECTION = "<tr> \n"
516: + " <td colspan=\"10\" class=\"header-left\"><small>{0}</small></td>\n"
517: + "</tr> \n"
518: + "<tr> \n"
519: + "<form method=\"get\" action=\"install\"> \n"
520: + "<input type=\"hidden\" name=\"path\"> \n"
521: + " <td colspan=\"10\" class=\"row-left\"> \n"
522: + " <small>{1}</small> \n"
523: + " <input type=\"text\" name=\"installPath\" size=\"10\"> \n"
524: + " <small>{2}</small> \n"
525: + " <input type=\"text\" name=\"installConfig\" size=\"18\"> \n"
526: + " <small>{3}</small> \n"
527: + " <input type=\"text\" name=\"installWar\" size=\"18\"> \n"
528: + " <input type=\"submit\" value=\"{4}\"> \n"
529: + " </td> \n" + "</form> \n" + "</tr> \n" + "</table> \n"
530: + "<br> \n" + "\n";
531:
532: private static final String SERVER_HEADER_SECTION = "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\"> \n"
533: + "<tr> \n"
534: + " <td colspan=\"10\" class=\"title\">{0}</td> \n"
535: + "</tr> \n"
536: + "<tr> \n"
537: + " <td class=\"header-center\"><small>{1}</small></td> \n"
538: + " <td class=\"header-center\"><small>{2}</small></td> \n"
539: + " <td class=\"header-center\"><small>{3}</small></td> \n"
540: + " <td class=\"header-center\"><small>{4}</small></td> \n"
541: + " <td class=\"header-center\"><small>{5}</small></td> \n"
542: + " <td class=\"header-center\"><small>{6}</small></td> \n"
543: + "</tr> \n";
544:
545: private static final String SERVER_ROW_SECTION = "<tr> \n"
546: + " <td class=\"row-center\"><small>{0}</small></td> \n"
547: + " <td class=\"row-center\"><small>{1}</small></td> \n"
548: + " <td class=\"row-center\"><small>{2}</small></td> \n"
549: + " <td class=\"row-center\"><small>{3}</small></td> \n"
550: + " <td class=\"row-center\"><small>{4}</small></td> \n"
551: + " <td class=\"row-center\"><small>{5}</small></td> \n"
552: + "</tr> \n" + "</table> \n" + "<br> \n" + "\n";
553:
554: private static final String HTML_TAIL_SECTION = "</body> \n"
555: + "</html>";
556: }
|