View Javadoc

1   /*
2    * Copyright 1999,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.catalina.servlets;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.net.URL;
25  import java.net.MalformedURLException;
26  import java.text.MessageFormat;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.Map;
31  import java.util.TreeMap;
32  import javax.servlet.ServletException;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  
36  import org.apache.catalina.Container;
37  import org.apache.catalina.Context;
38  import org.apache.catalina.Deployer;
39  import org.apache.catalina.Host;
40  import org.apache.catalina.util.ServerInfo;
41  import org.apache.commons.fileupload.FileItem;
42  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
43  import org.apache.commons.fileupload.servlet.ServletFileUpload;
44  
45  import org.talika.tms.Constants;
46  
47  /**
48  * Servlet that enables remote management of the web applications installed
49  * within the same virtual host as this web application is.  Normally, this
50  * functionality will be protected by a security constraint in the web
51  * application deployment descriptor.  However, this requirement can be
52  * relaxed during testing.
53  * <p>
54  * The difference between the <code>ManagerServlet</code> and this
55  * Servlet is that this Servlet prints out a HTML interface which
56  * makes it easier to administrate.
57  * <p>
58  * However if you use a software that parses the output of
59  * <code>ManagerServlet</code> you won't be able to upgrade
60  * to this Servlet since the output are not in the
61  * same format ar from <code>ManagerServlet</code>
62  *
63  * @author Bip Thelin
64  * @author Malcolm Edgar
65  * @author Glenn L. Nielsen
66  * @author Jose M. Palomar
67  * @version $Revision: 311 $, $Date: 2006-07-09 11:53:16 +0200 (dom 09 de jul de 2006) $
68  * @see ManagerXServlet
69  */
70  
71  public final class HTMLManagerXServlet extends ManagerXServlet {
72  
73      // --------------------------------------------------------- Public Methods
74  
75      /**
76       * Process a GET request for the specified resource.
77       *
78       * @param request The servlet request we are processing
79       * @param response The servlet response we are creating
80       *
81       * @exception IOException if an input/output error occurs
82       * @exception ServletException if a servlet-specified error occurs
83       */
84      public void doGet(HttpServletRequest request,
85                        HttpServletResponse response)
86          throws IOException, ServletException {
87  
88          // Identify the request parameters that we need
89          String command = request.getPathInfo();
90  
91          String vhost = request.getParameter("vhost");
92          String path = request.getParameter("path");
93          String installPath = request.getParameter("installPath");
94          String installConfig = request.getParameter("installConfig");
95          String installWar = request.getParameter("installWar");
96  
97          // Prepare our output writer to generate the response message
98          Locale locale = Locale.getDefault();
99          String charset = context.getCharsetMapper().getCharset(locale);
100         response.setLocale(locale);
101         response.setContentType("text/html; charset=" + charset);
102 
103         String message = "";
104         // Process the requested command
105         if (command == null || command.equals("/")) {
106         } else if (command.equals("/install")) {
107             message = install(vhost, installConfig, installPath, installWar);
108         } else if (command.equals("/vhosts")) {
109         } else if (command.equals("/list")) {
110         } else if (command.equals("/reload")) {
111             message = reload(vhost, path);
112         } else if (command.equals("/remove")) {
113             message = remove(vhost, path);
114         } else if (command.equals("/sessions")) {
115             message = sessions(vhost, path);
116         } else if (command.equals("/start")) {
117             message = start(vhost, path);
118         } else if (command.equals("/stop")) {
119             message = stop(vhost, path);
120         } else {
121             message =
122                 sm.getString("managerServlet.unknownCommand", command);
123         }
124 
125         list(request, response, vhost, message);
126     }
127 
128     /**
129      * Process a POST request for the specified resource.
130      *
131      * @param request The servlet request we are processing
132      * @param response The servlet response we are creating
133      *
134      * @exception IOException if an input/output error occurs
135      * @exception ServletException if a servlet-specified error occurs
136      */
137     public void doPost(HttpServletRequest request,
138                       HttpServletResponse response)
139         throws IOException, ServletException {
140 
141         // Identify the request parameters that we need
142         String command = request.getPathInfo();
143 
144         if (command == null || !command.equals("/upload")) {
145             doGet(request,response);
146             return;
147         }
148 
149         // Prepare our output writer to generate the response message
150         Locale locale = Locale.getDefault();
151         String charset = context.getCharsetMapper().getCharset(locale);
152         response.setLocale(locale);
153         response.setContentType("text/html; charset=" + charset);
154 
155         StringWriter stringWriter = new StringWriter();
156         PrintWriter writer = new PrintWriter(stringWriter);
157 
158         boolean uploadFailed = true;
159 
160         // Create a new file upload handler
161         DiskFileItemFactory factory = new DiskFileItemFactory();
162         factory.setRepository(deployed);
163         ServletFileUpload upload = new ServletFileUpload(factory);
164 
165         // Set upload parameters
166         upload.setSizeMax(-1);
167 
168         // Parse the request
169         String war = null;
170         FileItem warUpload = null;
171         File xmlFile = null;
172         String vhost = null;
173 
174         // There is a possible race condition here. If liveDeploy is true it
175         // means the deployer could start to deploy the app before we do it.
176         synchronized(getLock()) {
177             try {
178                 List items = upload.parseRequest(request);
179 
180                 // Process the uploaded fields
181                 Iterator iter = items.iterator();
182                 while (iter.hasNext()) {
183                     FileItem item = (FileItem) iter.next();
184 
185                     if (!item.isFormField()) {
186                         if (item.getFieldName().equals("installWar") &&
187                             warUpload == null) {
188                             warUpload = item;
189                         } else {
190                             item.delete();
191                         }
192                     }
193                     else {
194                         if (item.getFieldName().equals("vhost")) {
195                             vhost = item.getString();
196                         }
197                     }
198                 }
199                 while(true) {
200                     if (vhost == null) {
201                         writer.println(sm.getString
202                             ("managerServlet.invalidVirtualHost", vhost));
203                         break;
204                     }
205                     if (warUpload == null) {
206                         writer.println(sm.getString
207                             ("htmlManagerServlet.installUploadNoFile"));
208                         break;
209                     }
210                     war = warUpload.getName();
211                     if (!war.toLowerCase().endsWith(".war")) {
212                         writer.println(sm.getString
213                             ("htmlManagerServlet.installUploadNotWar",war));
214                         break;
215                     }
216                     // Get the filename if uploaded name includes a path
217                     if (war.lastIndexOf('\\') >= 0) {
218                         war = war.substring(war.lastIndexOf('\\') + 1);
219                     }
220                     if (war.lastIndexOf('/') >= 0) {
221                         war = war.substring(war.lastIndexOf('/') + 1);
222                     }
223 
224                     String xmlName = war.substring(0,war.length()-4) + ".xml";
225 
226                     // Identify the appBase of the owning Host of this Context
227                     // (if any)
228                     String appBase = null;
229                     File appBaseDir = null;
230                     appBase = ((Host) context.getParent()).getAppBase();
231                     appBaseDir = new File(appBase);
232                     if (!appBaseDir.isAbsolute()) {
233                         appBaseDir = new File(System.getProperty("catalina.base"),
234                                               appBase);
235                     }
236                     File file = new File(appBaseDir,war);
237                     if (file.exists()) {
238                         writer.println(sm.getString
239                             ("htmlManagerServlet.installUploadWarExists",war));
240                         break;
241                     }
242                     warUpload.write(file);
243                     try {
244                         URL url = file.toURL();
245                         war = url.toString();
246                         war = "jar:" + war + "!/";
247                     } catch(MalformedURLException e) {
248                         file.delete();
249                         throw e;
250                     }
251 
252                     // Extract the context.xml file, if any
253                     xmlFile = new File(appBaseDir, xmlName);
254                     extractXml(file, xmlFile);
255 
256                     uploadFailed = false;
257 
258                     break;
259                 }
260             } catch(Exception e) {
261                 String message = sm.getString
262                     ("htmlManagerServlet.installUploadFail", e.getMessage());
263                 log(message, e);
264                 writer.println(message);
265             } finally {
266                 if (warUpload != null) {
267                     warUpload.delete();
268                 }
269                 warUpload = null;
270             }
271         
272             // Define the context.xml URL if present
273             String xmlURL = null;
274             if (xmlFile != null && xmlFile.exists()) {
275                 xmlURL = new String("file:" + xmlFile.getAbsolutePath());
276             }
277     
278             // If there were no errors, install the WAR
279             if (!uploadFailed) {
280                 install(writer, vhost, xmlURL, null, war);
281             }
282 
283         }
284 
285 
286         String message = stringWriter.toString();
287 
288         list(request, response, vhost, message);
289     }
290 
291     /**
292      * Install an application for the specified path from the specified
293      * web application archive.
294      *
295      * @param vhost Virtual host to be listed
296      * @param config URL of the context configuration file to be installed
297      * @param path Context path of the application to be installed
298      * @param war URL of the web application archive to be installed
299      * @return message String
300      */
301     protected String install(String vhost, String config, String path, String war) {
302 
303         StringWriter stringWriter = new StringWriter();
304         PrintWriter printWriter = new PrintWriter(stringWriter);
305 
306         super.install(printWriter, vhost, config, path, war);
307 
308         return stringWriter.toString();
309     }
310 
311     /**
312      * Render a HTML list of the currently active Contexts in our virtual host,
313      * and memory and server status information.
314      *
315      * @param vhost Virtual host to be listed
316      * @param message a message to display
317      */
318     public void list(HttpServletRequest request,
319                      HttpServletResponse response,
320                      String vhost,
321                      String message) throws IOException {
322 
323         if (debug >= 1)
324             log("list: Listing contexts for virtual host '" +
325                 vhost + "'");
326 
327         Deployer deployer = null;
328         if(vhost != null && vhost.length() > 0) {
329 
330             deployer = (Deployer) engine.findChild(vhost);
331             if (deployer == null) {
332                 message = sm.getString("managerServlet.invalidVirtualHost", vhost);
333             }
334             
335         }
336         
337         PrintWriter writer = response.getWriter();
338 
339         // HTML Header Section
340         writer.print(HTML_HEADER_SECTION);
341 
342         // Body Header Section
343         Object[] args = new Object[2];
344         args[0] = request.getContextPath();
345         args[1] = sm.getString("htmlManagerServlet.title");
346         writer.print(MessageFormat.format(BODY_HEADER_SECTION, args));
347 
348         // Message Section
349         args = new Object[3];
350         args[0] = sm.getString("htmlManagerServlet.messageLabel");
351         args[1] = (message == null || message.length() == 0) ? "OK" : message;
352         writer.print(MessageFormat.format(MESSAGE_SECTION, args));
353 
354         if(deployer == null) {
355             
356             // Manager Section
357             args = new Object[7];
358             args[0] = sm.getString("htmlManagerServlet.manager");
359             args[1] = response.encodeURL(request.getContextPath() + "/html/vhosts");
360             args[2] = sm.getString("htmlManagerServlet.vhosts");
361             args[3] = response.encodeURL
362                 (request.getContextPath() + "/" +
363                  sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
364             args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
365             args[5] = response.encodeURL
366                 (request.getContextPath() + "/" +
367                  sm.getString("htmlManagerServlet.helpManagerFile"));
368             args[6] = sm.getString("htmlManagerServlet.helpManager");
369             writer.print(MessageFormat.format(MANAGERX_SECTION, args));
370             
371             // Vhosts Header Section
372             args = new Object[4];
373             args[0] = sm.getString("htmlManagerServlet.vhostsTitle");
374             args[1] = sm.getString("htmlManagerServlet.vhostsName");
375             args[2] = sm.getString("htmlManagerServlet.vhostsDefault");
376             args[3] = sm.getString("htmlManagerServlet.vhostsTasks");
377             writer.print(MessageFormat.format(VHOSTS_HEADER_SECTION, args));
378             
379             // Vhosts Row Section
380             Container hosts[] = engine.findChildren();
381     
382             String defaultHostName = engine.getDefaultHost();
383             String vhostsList = sm.getString("htmlManagerServlet.vhostsList");
384 
385             for (int i = 0; i < hosts.length; i++) {
386 
387                 String name = hosts[i].getName();
388                 boolean defaultHost = (name != null && name.equals(defaultHostName));
389     
390                 args = new Object[4];
391                 args[0] = name;
392                 args[1] = new Boolean(defaultHost);
393                 args[2] = response.encodeURL
394                         (request.getContextPath() + "/html/list?vhost=" + name);
395                 args[3] = vhostsList;
396                     writer.print
397                         (MessageFormat.format(VHOSTS_ROW_DETAILS_SECTION, args));
398                 
399             }
400             
401             writer.print(VHOSTS_FOOTER_SECTION);
402             
403         }
404         else {
405 
406             // Manager Section
407             args = new Object[7];
408             args[0] = sm.getString("htmlManagerServlet.manager");
409             args[1] = response.encodeURL(request.getContextPath() + 
410                                          "/html/list?vhost=" + vhost);
411             args[2] = sm.getString("htmlManagerServlet.list");
412             args[3] = response.encodeURL
413                 (request.getContextPath() + "/" +
414                  sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
415             args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
416             args[5] = response.encodeURL
417                 (request.getContextPath() + "/" +
418                  sm.getString("htmlManagerServlet.helpManagerFile"));
419             args[6] = sm.getString("htmlManagerServlet.helpManager");
420             writer.print(MessageFormat.format(MANAGERX_SECTION, args));
421             
422             // Apps Header Section
423             args = new Object[6];
424             args[0] = sm.getString("htmlManagerServlet.appsTitle") + " - " + vhost;
425             args[1] = sm.getString("htmlManagerServlet.appsPath");
426             args[2] = sm.getString("htmlManagerServlet.appsName");
427             args[3] = sm.getString("htmlManagerServlet.appsAvailable");
428             args[4] = sm.getString("htmlManagerServlet.appsSessions");
429             args[5] = sm.getString("htmlManagerServlet.appsTasks");
430             writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
431     
432             // Apps Row Section
433             // Create sorted map of deployed applications context paths.
434             String contextPaths[] = deployer.findDeployedApps();
435     
436             TreeMap sortedContextPathsMap = new TreeMap();
437     
438             for (int i = 0; i < contextPaths.length; i++) {
439                 String displayPath = contextPaths[i];
440                 sortedContextPathsMap.put(displayPath, contextPaths[i]);
441             }
442     
443             String appsStart = sm.getString("htmlManagerServlet.appsStart");
444             String appsStop = sm.getString("htmlManagerServlet.appsStop");
445             String appsReload = sm.getString("htmlManagerServlet.appsReload");
446             String appsRemove = sm.getString("htmlManagerServlet.appsRemove");
447     
448             Iterator iterator = sortedContextPathsMap.entrySet().iterator();
449             while (iterator.hasNext()) {
450                 Map.Entry entry = (Map.Entry) iterator.next();
451                 String displayPath = (String) entry.getKey();
452                 String contextPath = (String) entry.getKey();
453                 Context context = deployer.findDeployedApp(contextPath);
454                 if (displayPath.equals("")) {
455                     displayPath = "/";
456                 }
457     
458                 if (context != null ) {
459                     args = new Object[5];
460                     args[0] = displayPath;
461                     args[1] = context.getDisplayName();
462                     if (args[1] == null) {
463                         args[1] = "&nbsp;";
464                     }
465                     args[2] = new Boolean(context.getAvailable());
466                     args[3] = response.encodeURL
467                         (request.getContextPath() +
468                          "/html/sessions?vhost=" + vhost + "&path=" + displayPath);
469                     args[4] =
470                         new Integer(context.getManager().findSessions().length);
471                     writer.print
472                         (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args));
473     
474                     args = new Object[8];
475                     args[0] = response.encodeURL
476                         (request.getContextPath() +
477                          "/html/start?vhost=" + vhost + "&path=" + displayPath);
478                     args[1] = appsStart;
479                     args[2] = response.encodeURL
480                         (request.getContextPath() +
481                          "/html/stop?vhost=" + vhost + "&path=" + displayPath);
482                     args[3] = appsStop;
483                     args[4] = response.encodeURL
484                         (request.getContextPath() +
485                          "/html/reload?vhost=" + vhost + "&path=" + displayPath);
486                     args[5] = appsReload;
487                     args[6] = response.encodeURL
488                         (request.getContextPath() +
489                          "/html/remove?vhost=" + vhost + "&path=" + displayPath);
490                     args[7] = appsRemove;
491                     if (context.getPath().equals(this.context.getPath())) {
492                         writer.print(MessageFormat.format(
493                             MANAGER_APP_ROW_BUTTON_SECTION, args));
494                     } else if (context.getAvailable()) {
495                         writer.print(MessageFormat.format(
496                             STARTED_APPS_ROW_BUTTON_SECTION, args));
497                     } else {
498                         writer.print(MessageFormat.format(
499                             STOPPED_APPS_ROW_BUTTON_SECTION, args));
500                     }
501     
502                 }
503 
504             }
505     
506             // Install Section
507             args = new Object[8];
508             args[0] = sm.getString("htmlManagerServlet.installTitle");
509             args[1] = sm.getString("htmlManagerServlet.installServer");
510             args[2] = response.encodeURL(request.getContextPath() + "/html/install");
511             args[3] = vhost;
512             args[4] = sm.getString("htmlManagerServlet.installPath");
513             args[5] = sm.getString("htmlManagerServlet.installConfig");
514             args[6] = sm.getString("htmlManagerServlet.installWar");
515             args[7] = sm.getString("htmlManagerServlet.installButton");
516             writer.print(MessageFormat.format(INSTALL_SECTION, args));
517     
518             args = new Object[5];
519             args[0] = sm.getString("htmlManagerServlet.installUpload");
520             args[1] = response.encodeURL(request.getContextPath() + "/html/upload");
521             args[2] = vhost; 
522             args[3] = sm.getString("htmlManagerServlet.installUploadFile");
523             args[4] = sm.getString("htmlManagerServlet.installButton");
524             writer.print(MessageFormat.format(UPLOAD_SECTION, args));
525 
526         }
527         
528         // Server Header Section
529         args = new Object[7];
530         args[0] = sm.getString("htmlManagerServlet.serverTitle");
531         args[1] = sm.getString("htmlManagerServlet.serverVersion");
532         args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
533         args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
534         args[4] = sm.getString("htmlManagerServlet.serverOSName");
535         args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
536         args[6] = sm.getString("htmlManagerServlet.serverOSArch");
537         writer.print(MessageFormat.format(SERVER_HEADER_SECTION, args));
538 
539         // Server Row Section
540         args = new Object[6];
541         args[0] = ServerInfo.getServerInfo();
542         args[1] = System.getProperty("java.runtime.version");
543         args[2] = System.getProperty("java.vm.vendor");
544         args[3] = System.getProperty("os.name");
545         args[4] = System.getProperty("os.version");
546         args[5] = System.getProperty("os.arch");
547         writer.print(MessageFormat.format(SERVER_ROW_SECTION, args));
548 
549         // HTML Tail Section
550         writer.print(HTML_TAIL_SECTION);
551 
552         // Finish up the response
553         writer.flush();
554         writer.close();
555     }
556 
557     /**
558      * Reload the web application at the specified context path.
559      *
560      * @see ManagerXServlet#reload(PrintWriter, String)
561      *
562      * @param vhost Virtual host to be listed
563      * @param path Context path of the application to be restarted
564      * @return message String
565      */
566     protected String reload(String vhost, String path) {
567 
568         StringWriter stringWriter = new StringWriter();
569         PrintWriter printWriter = new PrintWriter(stringWriter);
570 
571         super.reload(printWriter, vhost, path);
572 
573         return stringWriter.toString();
574     }
575 
576     /**
577      * Remove the web application at the specified context path.
578      *
579      * @see ManagerXServlet#remove(PrintWriter, String)
580      *
581      * @param path Context path of the application to be removed
582      * @return message String
583      */
584     protected String remove(String vhost, String path) {
585 
586         StringWriter stringWriter = new StringWriter();
587         PrintWriter printWriter = new PrintWriter(stringWriter);
588 
589         super.remove(printWriter, vhost, path);
590 
591         return stringWriter.toString();
592     }
593 
594     /**
595      * Display session information and invoke list.
596      *
597      * @see ManagerXServlet#sessions(PrintWriter, String)
598      *
599      * @param vhost Virtual host to be listed
600      * @param path Context path of the application to list session information
601      * @return message String
602      */
603     public String sessions(String vhost, String path) {
604 
605         StringWriter stringWriter = new StringWriter();
606         PrintWriter printWriter = new PrintWriter(stringWriter);
607 
608         super.sessions(printWriter, vhost, path);
609 
610         return stringWriter.toString();
611     }
612 
613     /**
614      * Start the web application at the specified context path.
615      *
616      * @see ManagerXServlet#start(PrintWriter, String)
617      *
618      * @param vhost Virtual host to be listed
619      * @param path Context path of the application to be started
620      * @return message String
621      */
622     public String start(String vhost, String path) {
623 
624         StringWriter stringWriter = new StringWriter();
625         PrintWriter printWriter = new PrintWriter(stringWriter);
626 
627         super.start(printWriter, vhost, path);
628 
629         return stringWriter.toString();
630     }
631 
632     /**
633      * Stop the web application at the specified context path.
634      *
635      * @see ManagerXServlet#stop(PrintWriter, String)
636      *
637      * @param vhost Virtual host to be listed
638      * @param path Context path of the application to be stopped
639      * @return message String
640      */
641     protected String stop(String vhost, String path) {
642 
643         StringWriter stringWriter = new StringWriter();
644         PrintWriter printWriter = new PrintWriter(stringWriter);
645 
646         super.stop(printWriter, vhost, path);
647 
648         return stringWriter.toString();
649     }
650 
651     // ------------------------------------------------------ Private Constants
652 
653     // These HTML sections are broken in relatively small sections, because of
654     // limited number of subsitutions MessageFormat can process
655     // (maximium of 10).
656 
657     private static final String HTML_HEADER_SECTION =
658         "<html>\n" +
659         "<head>\n" +
660         "<style>\n" +
661         "  table { width: 100%; }\n" +
662         "  td.page-title {\n" +
663         "    text-align: center;\n" +
664         "    vertical-align: top;\n" +
665         "    font-family:verdana,sans-serif;\n" +
666         "    font-weight: bold;\n" +
667         "    background: white;\n" +
668         "    color: black;\n" +
669         "  }\n" +
670         "  td.title {\n" +
671         "    text-align: left;\n" +
672         "    vertical-align: top;\n" +
673         "    font-family:verdana,sans-serif;\n" +
674         "    font-style:italic;\n" +
675         "    font-weight: bold;\n" +
676         "    background: #D2A41C;\n" +
677         "  }\n" +
678         "  td.header-left {\n" +
679         "    text-align: left;\n" +
680         "    vertical-align: top;\n" +
681         "    font-family:verdana,sans-serif;\n" +
682         "    font-weight: bold;\n" +
683         "    background: #FFDC75;\n" +
684         "  }\n" +
685         "  td.header-center {\n" +
686         "    text-align: center;\n" +
687         "    vertical-align: top;\n" +
688         "    font-family:verdana,sans-serif;\n" +
689         "    font-weight: bold;\n" +
690         "    background: #FFDC75;\n" +
691         "  }\n" +
692         "  td.row-left {\n" +
693         "    text-align: left;\n" +
694         "    vertical-align: middle;\n" +
695         "    font-family:verdana,sans-serif;\n" +
696         "    color: black;\n" +
697         "    background: white;\n" +
698         "  }\n" +
699         "  td.row-center {\n" +
700         "    text-align: center;\n" +
701         "    vertical-align: middle;\n" +
702         "    font-family:verdana,sans-serif;\n" +
703         "    color: black;\n" +
704         "    background: white;\n" +
705         "  }\n" +
706         "  td.row-right {\n" +
707         "    text-align: right;\n" +
708         "    vertical-align: middle;\n" +
709         "    font-family:verdana,sans-serif;\n" +
710         "    color: black;\n" +
711         "    background: white;\n" +
712         "  }\n" +
713         "</style>\n";
714 
715     private static final String BODY_HEADER_SECTION =
716         "<title>{0}</title>\n" +
717         "</head>\n" +
718         "\n" +
719         "<body bgcolor=\"#FFFFFF\">\n" +
720         "\n" +
721         "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
722         " <tr>\n" +
723         "  <td colspan=\"2\">\n" +
724         "   <a href=\"http://www.apache.org/\">\n" +
725         "    <img border=\"0\" alt=\"The Apache Software Foundation\""+
726         "         align=\"left\"\n src=\"{0}/images/asf-logo.gif\">\n" +
727         "   </a>\n" +
728         "   <a href=\"http://tomcat.apache.org/\">\n" +
729         "    <img border=\"0\" alt=\"The Tomcat Servlet/JSP Container\"\n" +
730         "         align=\"right\" src=\"{0}/images/tomcat.gif\">\n" +
731         "   </a>\n" +
732         "  </td>\n" +
733         " </tr>\n" +
734         "</table>\n" +
735         "<hr size=\"1\" noshade=\"noshade\">\n" +
736         "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
737         " <tr>\n" +
738         "  <td class=\"page-title\" bordercolor=\"#000000\" " +
739         "align=\"left\" nowrap>\n" +
740         "   <font size=\"+2\">{1}</font>\n" +
741         "  </td>\n" +
742         " </tr>\n" +
743         "</table>\n" +
744         "<br>\n" +
745         "\n";
746 
747     private static final String MESSAGE_SECTION =
748         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
749         " <tr>\n" +
750         "  <td class=\"row-left\" width=\"10%\">" +
751         "<small><b>{0}</b></small>&nbsp;</td>\n" +
752         "  <td class=\"row-left\"><pre>{1}</pre></td>\n" +
753         " </tr>\n" +
754         "</table>\n" +
755         "<br>\n" +
756         "\n";
757 
758     private static final String MANAGERX_SECTION =
759         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
760         "<tr>\n" +
761         " <td colspan=\"3\" class=\"title\">{0}</td>\n" +
762         "</tr>\n" +
763         " <tr>\n" +
764         "  <td class=\"row-left\"><a href=\"{1}\">{2}</a></td>\n" +
765         "  <td class=\"row-center\"><a href=\"{3}\">{4}</a></td>\n" +
766         "  <td class=\"row-right\"><a href=\"{5}\">{6}</a></td>\n" +
767         " </tr>\n" +
768         "</table>\n" +
769         "<br>\n" +
770         "\n";
771 
772     private static final String VHOSTS_HEADER_SECTION =
773         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
774         "<tr>\n" +
775         " <td colspan=\"3\" class=\"title\">{0}</td>\n" +
776         "</tr>\n" +
777         "<tr>\n" +
778         " <td class=\"header-left\"><small>{1}</small></td>\n" +
779         " <td class=\"header-center\"><small>{2}</small></td>\n" +
780         " <td class=\"header-left\"><small>{3}</small></td>\n" +
781         "</tr>\n";
782 
783     private static final String VHOSTS_ROW_DETAILS_SECTION =
784         "<tr>\n" +
785         " <td class=\"row-left\"><small>{0}</small></td>\n" +
786         " <td class=\"row-center\"><small>{1}</small></td>\n" +
787         " <td class=\"row-left\"><small><a href=\"{2}\">{3}</a></small></td>\n" +
788         "</tr>\n";
789 
790     private static final String VHOSTS_FOOTER_SECTION =
791         "</table>\n" +
792         "<br>\n";
793     
794     private static final String APPS_HEADER_SECTION =
795         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
796         "<tr>\n" +
797         " <td colspan=\"5\" class=\"title\">{0}</td>\n" +
798         "</tr>\n" +
799         "<tr>\n" +
800         " <td class=\"header-left\"><small>{1}</small></td>\n" +
801         " <td class=\"header-left\"><small>{2}</small></td>\n" +
802         " <td class=\"header-center\"><small>{3}</small></td>\n" +
803         " <td class=\"header-center\"><small>{4}</small></td>\n" +
804         " <td class=\"header-center\"><small>{5}</small></td>\n" +
805         "</tr>\n";
806 
807     private static final String APPS_ROW_DETAILS_SECTION =
808         "<tr>\n" +
809         " <td class=\"row-left\"><small><a href=\"{0}\">{0}</a>" +
810         "</small></td>\n" +
811         " <td class=\"row-left\"><small>{1}</small></td>\n" +
812         " <td class=\"row-center\"><small>{2}</small></td>\n" +
813         " <td class=\"row-center\">" +
814         "<small><a href=\"{3}\">{4}</a></small></td>\n";
815 
816     private static final String MANAGER_APP_ROW_BUTTON_SECTION =
817         " <td class=\"row-left\">\n" +
818         "  <small>\n" +
819         "  &nbsp;{1}&nbsp;\n" +
820         "  &nbsp;{3}&nbsp;\n" +
821         "  &nbsp;{5}&nbsp;\n" +
822         "  &nbsp;{7}&nbsp;\n" +
823         "  </small>\n" +
824         " </td>\n" +
825         "</tr>\n";
826 
827     private static final String STARTED_APPS_ROW_BUTTON_SECTION =
828         " <td class=\"row-left\">\n" +
829         "  <small>\n" +
830         "  &nbsp;{1}&nbsp;\n" +
831         "  &nbsp;<a href=\"{2}\">{3}</a>&nbsp;\n" +
832         "  &nbsp;<a href=\"{4}\">{5}</a>&nbsp;\n" +
833         "  &nbsp;<a href=\"{6}\">{7}</a>&nbsp;\n" +
834         "  </small>\n" +
835         " </td>\n" +
836         "</tr>\n";
837 
838     private static final String STOPPED_APPS_ROW_BUTTON_SECTION =
839         " <td class=\"row-left\">\n" +
840         "  <small>\n" +
841         "  &nbsp;<a href=\"{0}\">{1}</a>&nbsp;\n" +
842         "  &nbsp;{3}&nbsp;\n" +
843         "  &nbsp;{5}&nbsp;\n" +
844         "  &nbsp;<a href=\"{6}\">{7}</a>&nbsp;\n" +
845         "  </small>\n" +
846         " </td>\n" +
847         "</tr>\n";
848 
849     private static final String INSTALL_SECTION =
850         "</table>\n" +
851         "<br>\n" +
852         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
853         "<tr>\n" +
854         " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
855         "</tr>\n" +
856         "<tr>\n" +
857         " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
858         "</tr>\n" +
859         "<tr>\n" +
860         " <td colspan=\"2\">\n" +
861         "<form method=\"get\" action=\"{2}\">\n" +
862         "<input type=\"hidden\" name=\"vhost\" value=\"{3}\">\n" +
863         "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
864         "<tr>\n" +
865         " <td class=\"row-right\">\n" +
866         "  <small>{4}</small>\n" +
867         " </td>\n" +
868         " <td class=\"row-left\">\n" +
869         "  <input type=\"text\" name=\"installPath\" size=\"20\">\n" +
870         " </td>\n" +
871         "</tr>\n" +
872         "<tr>\n" +
873         " <td class=\"row-right\">\n" +
874         "  <small>{5}</small>\n" +
875         " </td>\n" +
876         " <td class=\"row-left\">\n" +
877         "  <input type=\"text\" name=\"installConfig\" size=\"20\">\n" +
878         " </td>\n" +
879         "</tr>\n" +
880         "<tr>\n" +
881         " <td class=\"row-right\">\n" +
882         "  <small>{6}</small>\n" +
883         " </td>\n" +
884         " <td class=\"row-left\">\n" +
885         "  <input type=\"text\" name=\"installWar\" size=\"40\">\n" +
886         " </td>\n" +
887         "</tr>\n" +
888         "<tr>\n" +
889         " <td class=\"row-right\">\n" +
890         "  &nbsp;\n" +
891         " </td>\n" +
892         " <td class=\"row-left\">\n" +
893         "  <input type=\"submit\" value=\"{7}\">\n" +
894         " </td>\n" +
895         "</tr>\n" +
896         "</table>\n" +
897         "</form>\n" +
898         "</td>\n" +
899         "</tr>\n";
900 
901     private static final String UPLOAD_SECTION =
902         "<tr>\n" +
903         " <td colspan=\"2\" class=\"header-left\"><small>{0}</small></td>\n" +
904         "</tr>\n" +
905         "<tr>\n" +
906         " <td colspan=\"2\">\n" +
907         "<form action=\"{1}\" method=\"post\" " +
908         "enctype=\"multipart/form-data\">\n" +
909         "<input type=\"hidden\" name=\"vhost\" value=\"{2}\">\n" +
910         "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
911         "<tr>\n" +
912         " <td class=\"row-right\">\n" +
913         "  <small>{3}</small>\n" +
914         " </td>\n" +
915         " <td class=\"row-left\">\n" +
916         "  <input type=\"file\" name=\"installWar\" size=\"40\">\n" +
917         " </td>\n" +
918         "</tr>\n" +
919         "<tr>\n" +
920         " <td class=\"row-right\">\n" +
921         "  &nbsp;\n" +
922         " </td>\n" +
923         " <td class=\"row-left\">\n" +
924         "  <input type=\"submit\" value=\"{4}\">\n" +
925         " </td>\n" +
926         "</tr>\n" +
927         "</table>\n" +
928         "</form>\n" +
929         "</table>\n" +
930         "<br>\n" +
931         "\n";
932 
933     private static final String SERVER_HEADER_SECTION =
934         "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
935         "<tr>\n" +
936         " <td colspan=\"6\" class=\"title\">{0}</td>\n" +
937         "</tr>\n" +
938         "<tr>\n" +
939         " <td class=\"header-center\"><small>{1}</small></td>\n" +
940         " <td class=\"header-center\"><small>{2}</small></td>\n" +
941         " <td class=\"header-center\"><small>{3}</small></td>\n" +
942         " <td class=\"header-center\"><small>{4}</small></td>\n" +
943         " <td class=\"header-center\"><small>{5}</small></td>\n" +
944         " <td class=\"header-center\"><small>{6}</small></td>\n" +
945         "</tr>\n";
946 
947     private static final String SERVER_ROW_SECTION =
948         "<tr>\n" +
949         " <td class=\"row-center\"><small>{0}</small></td>\n" +
950         " <td class=\"row-center\"><small>{1}</small></td>\n" +
951         " <td class=\"row-center\"><small>{2}</small></td>\n" +
952         " <td class=\"row-center\"><small>{3}</small></td>\n" +
953         " <td class=\"row-center\"><small>{4}</small></td>\n" +
954         " <td class=\"row-center\"><small>{5}</small></td>\n" +
955         "</tr>\n" +
956         "</table>\n" +
957         "<br>\n" +
958         "\n";
959 
960     private static final String HTML_TAIL_SECTION =
961         "<hr size=\"1\" noshade=\"noshade\">\n" +
962         "<center><font size=\"-1\" color=\"#525D76\">\n" +
963         " <em>Copyright &copy; 1999-2002, Apache Software Foundation</em>" +
964         "</font></center>\n" +
965         "\n" +
966         "</body>\n" +
967         "</html>";
968 }