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.manager;
19  
20  
21  import java.io.BufferedOutputStream;
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.util.Iterator;
28  
29  import javax.management.MBeanServer;
30  import javax.management.ObjectName;
31  import javax.naming.Binding;
32  import javax.naming.InitialContext;
33  import javax.naming.NamingEnumeration;
34  import javax.naming.NamingException;
35  import javax.servlet.ServletException;
36  import javax.servlet.ServletInputStream;
37  import javax.servlet.UnavailableException;
38  import javax.servlet.http.HttpServlet;
39  import javax.servlet.http.HttpServletRequest;
40  import javax.servlet.http.HttpServletResponse;
41  import org.apache.catalina.Container;
42  import org.apache.catalina.ContainerServlet;
43  import org.apache.catalina.Context;
44  import org.apache.catalina.Engine;
45  import org.apache.catalina.Globals;
46  import org.apache.catalina.Host;
47  import org.apache.catalina.Lifecycle;
48  import org.apache.catalina.Role;
49  import org.apache.catalina.Server;
50  import org.apache.catalina.ServerFactory;
51  import org.apache.catalina.Session;
52  import org.apache.catalina.UserDatabase;
53  import org.apache.catalina.Wrapper;
54  import org.apache.catalina.core.StandardServer;
55  import org.apache.catalina.util.RequestUtil;
56  import org.apache.catalina.util.ServerInfo;
57  import org.apache.catalina.util.StringManager;
58  import org.apache.commons.modeler.Registry;
59  
60  import org.talika.tms.Constants;
61  
62  
63  /**
64   * Servlet that enables remote management of the web applications installed
65   * within the same virtual host as this web application is.  Normally, this
66   * functionality will be protected by a security constraint in the web
67   * application deployment descriptor.  However, this requirement can be
68   * relaxed during testing.
69   * <p>
70   * This servlet examines the value returned by <code>getPathInfo()</code>
71   * and related query parameters to determine what action is being requested.
72   * The following actions and parameters (starting after the servlet path)
73   * are supported:
74   * <ul>
75   * <li><b>/deploy?config={config-url}</b> - Install and start a new
76   *     web application, based on the contents of the context configuration
77   *     file found at the specified URL.  The <code>docBase</code> attribute
78   *     of the context configuration file is used to locate the actual
79   *     WAR or directory containing the application.</li>
80   * <li><b>/deploy?config={config-url}&war={war-url}/</b> - Install and start
81   *     a new web application, based on the contents of the context
82   *     configuration file found at <code>{config-url}</code>, overriding the
83   *     <code>docBase</code> attribute with the contents of the web
84   *     application archive found at <code>{war-url}</code>.</li>
85   * <li><b>/deploy?path=/xxx&war={war-url}</b> - Install and start a new
86   *     web application attached to context path <code>/xxx</code>, based
87   *     on the contents of the web application archive found at the
88   *     specified URL.</li>
89   * <li><b>/list</b> - List the context paths of all currently installed web
90   *     applications for this virtual host.  Each context will be listed with
91   *     the following format <code>path:status:sessions</code>.
92   *     Where path is the context path.  Status is either running or stopped.
93   *     Sessions is the number of active Sessions.</li>
94   * <li><b>/reload?path=/xxx</b> - Reload the Java classes and resources for
95   *     the application at the specified path.</li>
96   * <li><b>/resources?type=xxxx</b> - Enumerate the available global JNDI
97   *     resources, optionally limited to those of the specified type
98   *     (fully qualified Java class name), if available.</li>
99   * <li><b>/roles</b> - Enumerate the available security role names and
100  *     descriptions from the user database connected to the <code>users</code>
101  *     resource reference.
102  * <li><b>/serverinfo</b> - Display system OS and JVM properties.
103  * <li><b>/sessions?path=/xxx</b> - List session information about the web
104  *     application attached to context path <code>/xxx</code> for this
105  *     virtual host.</li>
106  * <li><b>/start?path=/xxx</b> - Start the web application attached to
107  *     context path <code>/xxx</code> for this virtual host.</li>
108  * <li><b>/stop?path=/xxx</b> - Stop the web application attached to
109  *     context path <code>/xxx</code> for this virtual host.</li>
110  * <li><b>/undeploy?path=/xxx</b> - Shutdown and remove the web application
111  *     attached to context path <code>/xxx</code> for this virtual host,
112  *     and remove the underlying WAR file or document base directory.
113  *     (<em>NOTE</em> - This is only allowed if the WAR file or document
114  *     base is stored in the <code>appBase</code> directory of this host,
115  *     typically as a result of being placed there via the <code>/deploy</code>
116  *     command.</li>
117  * </ul>
118  * <p>Use <code>path=/</code> for the ROOT context.</p>
119  * <p>The syntax of the URL for a web application archive must conform to one
120  * of the following patterns to be successfully deployed:</p>
121  * <ul>
122  * <li><b>file:/absolute/path/to/a/directory</b> - You can specify the absolute
123  *     path of a directory that contains the unpacked version of a web
124  *     application.  This directory will be attached to the context path you
125  *     specify without any changes.</li>
126  * <li><b>jar:file:/absolute/path/to/a/warfile.war!/</b> - You can specify a
127  *     URL to a local web application archive file.  The syntax must conform to
128  *     the rules specified by the <code>JarURLConnection</code> class for a
129  *     reference to an entire JAR file.</li>
130  * <li><b>jar:http://hostname:port/path/to/a/warfile.war!/</b> - You can specify
131  *     a URL to a remote (HTTP-accessible) web application archive file.  The
132  *     syntax must conform to the rules specified by the
133  *     <code>JarURLConnection</code> class for a reference to an entire
134  *     JAR file.</li>
135  * </ul>
136  * <p>
137  * <b>NOTE</b> - Attempting to reload or remove the application containing
138  * this servlet itself will not succeed.  Therefore, this servlet should
139  * generally be deployed as a separate web application within the virtual host
140  * to be managed.
141  * <p>
142  * <b>NOTE</b> - For security reasons, this application will not operate
143  * when accessed via the invoker servlet.  You must explicitly map this servlet
144  * with a servlet mapping, and you will always want to protect it with
145  * appropriate security constraints as well.
146  * <p>
147  * The following servlet initialization parameters are recognized:
148  * <ul>
149  * <li><b>debug</b> - The debugging detail level that controls the amount
150  *     of information that is logged by this servlet.  Default is zero.
151  * </ul>
152  *
153  * @author Craig R. McClanahan
154  * @author Remy Maucherat
155  * @author Jose M. Palomar
156  * @version $Revision: 305 $ $Date: 2006-04-16 11:59:14 +0200 (dom 16 de abr de 2006) $
157  * 
158  * @todo Test more deploy functions over multiple hosts.
159  */
160 
161 public class ManagerXServlet
162     extends HttpServlet implements ContainerServlet {
163 
164 
165     // ----------------------------------------------------- Instance Variables
166 
167 
168     /**
169      * Path where context descriptors should be deployed.
170      */
171     protected File configBase = null;
172 
173 
174     /**
175      * The Context container associated with our web application.
176      */
177     protected Context context = null;
178 
179 
180     /**
181      * The debugging detail level for this servlet.
182      */
183     protected int debug = 1;
184 
185 
186     /**
187      * Path used to store revisions of webapps.
188      */
189     protected File versioned = null;
190 
191 
192     /**
193      * Path used to store context descriptors.
194      */
195     protected File contextDescriptors = null;
196 
197 
198     /**
199      * The Engine container of all our vhosts
200      */
201     protected Engine engine = null;
202 
203 
204     /**
205      * The host appBase.
206      */
207     protected File appBase = null;
208     
209     
210     /**
211      * MBean server.
212      */
213     protected MBeanServer mBeanServer = null;
214 
215 
216     /**
217      * The global JNDI <code>NamingContext</code> for this server,
218      * if available.
219      */
220     protected javax.naming.Context global = null;
221 
222 
223     /**
224      * The string manager for this package.
225      */
226     protected static StringManager sm =
227         StringManager.getManager(Constants.Package);
228 
229 
230     /**
231      * The Wrapper container associated with this servlet.
232      */
233     protected Wrapper wrapper = null;
234 
235 
236     // ----------------------------------------------- ContainerServlet Methods
237 
238 
239     /**
240      * Return the Wrapper with which we are associated.
241      */
242     public Wrapper getWrapper() {
243 
244         return (this.wrapper);
245 
246     }
247 
248 
249     /**
250      * Set the Wrapper with which we are associated.
251      *
252      * @param wrapper The new wrapper
253      */
254     public void setWrapper(Wrapper wrapper) {
255 
256         this.wrapper = wrapper;
257         if (wrapper == null) {
258             context = null;
259             engine = null;
260         } else {
261             context = (Context) wrapper.getParent();
262             engine = (Engine) context.getParent().getParent();
263         }
264 
265         // Retrieve the MBean server
266         mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
267         
268     }
269 
270 
271     // --------------------------------------------------------- Public Methods
272 
273 
274     /**
275      * Finalize this servlet.
276      */
277     public void destroy() {
278 
279         ;       // No actions necessary
280 
281     }
282 
283 
284     /**
285      * Process a GET request for the specified resource.
286      *
287      * @param request The servlet request we are processing
288      * @param response The servlet response we are creating
289      *
290      * @exception IOException if an input/output error occurs
291      * @exception ServletException if a servlet-specified error occurs
292      */
293     public void doGet(HttpServletRequest request,
294                       HttpServletResponse response)
295         throws IOException, ServletException {
296 
297         // Verify that we were not accessed using the invoker servlet
298         if (request.getAttribute(Globals.INVOKED_ATTR) != null)
299             throw new UnavailableException
300                 (sm.getString("managerServlet.cannotInvoke"));
301 
302         // Identify the request parameters that we need
303         String command = request.getPathInfo();
304         if (command == null)
305             command = request.getServletPath();
306         String vhost = request.getParameter("vhost");
307         String config = request.getParameter("config");
308         String path = request.getParameter("path");
309         String type = request.getParameter("type");
310         String war = request.getParameter("war");
311         String tag = request.getParameter("tag");
312         boolean update = false;
313         if ((request.getParameter("update") != null) 
314             && (request.getParameter("update").equals("true"))) {
315             update = true;
316         }
317 
318         // Prepare our output writer to generate the response message
319         response.setContentType("text/plain; charset=" + Constants.CHARSET);
320         PrintWriter writer = response.getWriter();
321 
322         // Process the requested command (note - "/deploy" is not listed here)
323         if (command == null) {
324             writer.println(sm.getString("managerServlet.noCommand"));
325         } else if (command.equals("/deploy")) {
326             if (war != null) {
327                 deploy(writer, vhost, config, path, war, update);
328             } else {
329                 deploy(writer, vhost, path, tag);
330             }
331         } else if (command.equals("/install")) {
332             // Deprecated
333             deploy(writer, vhost, config, path, war, false);
334         } else if (command.equals("/vhosts")) {
335             vhosts(writer);
336         } else if (command.equals("/list")) {
337             list(writer, vhost);
338         } else if (command.equals("/reload")) {
339             reload(writer, vhost, path);
340         } else if (command.equals("/remove")) {
341             // Deprecated
342             undeploy(writer, vhost, path);
343         } else if (command.equals("/resources")) {
344             resources(writer, type);
345         } else if (command.equals("/roles")) {
346             roles(writer);
347         } else if (command.equals("/save")) {
348             save(writer, vhost, path);
349         } else if (command.equals("/serverinfo")) {
350             serverinfo(writer);
351         } else if (command.equals("/sessions")) {
352             sessions(writer, vhost, path);
353         } else if (command.equals("/start")) {
354             start(writer, vhost, path);
355         } else if (command.equals("/stop")) {
356             stop(writer, vhost, path);
357         } else if (command.equals("/undeploy")) {
358             undeploy(writer, vhost, path);
359         } else {
360             writer.println(sm.getString("managerServlet.unknownCommand",
361                                         command));
362         }
363 
364         // Finish up the response
365         writer.flush();
366         writer.close();
367 
368     }
369 
370 
371     /**
372      * Process a PUT request for the specified resource.
373      *
374      * @param request The servlet request we are processing
375      * @param response The servlet response we are creating
376      *
377      * @exception IOException if an input/output error occurs
378      * @exception ServletException if a servlet-specified error occurs
379      */
380     public void doPut(HttpServletRequest request,
381                       HttpServletResponse response)
382         throws IOException, ServletException {
383 
384         // Verify that we were not accessed using the invoker servlet
385         if (request.getAttribute(Globals.INVOKED_ATTR) != null)
386             throw new UnavailableException
387                 (sm.getString("managerServlet.cannotInvoke"));
388 
389         // Identify the request parameters that we need
390         String command = request.getPathInfo();
391         if (command == null)
392             command = request.getServletPath();
393         String vhost = request.getParameter("vhost");
394         String path = request.getParameter("path");
395         String tag = request.getParameter("tag");
396         boolean update = false;
397         if ((request.getParameter("update") != null) 
398             && (request.getParameter("update").equals("true"))) {
399             update = true;
400         }
401 
402         // Prepare our output writer to generate the response message
403         response.setContentType("text/plain;charset="+Constants.CHARSET);
404         PrintWriter writer = response.getWriter();
405 
406         // Process the requested command
407         if (command == null) {
408             writer.println(sm.getString("managerServlet.noCommand"));
409         } else if (command.equals("/deploy")) {
410             deploy(writer, vhost, path, tag, update, request);
411         } else {
412             writer.println(sm.getString("managerServlet.unknownCommand",
413                                         command));
414         }
415 
416         // Finish up the response
417         writer.flush();
418         writer.close();
419 
420     }
421 
422 
423     /**
424      * Initialize this servlet.
425      */
426     public void init() throws ServletException {
427 
428         // Ensure that our ContainerServlet properties have been set
429         if ((wrapper == null) || (context == null))
430             throw new UnavailableException
431                 (sm.getString("managerServlet.noWrapper"));
432 
433         // Verify that we were not accessed using the invoker servlet
434         String servletName = getServletConfig().getServletName();
435         if (servletName == null)
436             servletName = "";
437         if (servletName.startsWith("org.apache.catalina.INVOKER."))
438             throw new UnavailableException
439                 (sm.getString("managerServlet.cannotInvoke"));
440 
441         // Set our properties from the initialization parameters
442         String value = null;
443         try {
444             value = getServletConfig().getInitParameter("debug");
445             debug = Integer.parseInt(value);
446         } catch (Throwable t) {
447             ;
448         }
449 
450         // Acquire global JNDI resources if available
451         Server server = ServerFactory.getServer();
452         if ((server != null) && (server instanceof StandardServer)) {
453             global = ((StandardServer) server).getGlobalNamingContext();
454         }
455 
456         // Calculate the directory into which we will be deploying applications
457         versioned = (File) getServletContext().getAttribute
458             ("javax.servlet.context.tempdir");
459 
460         configBase = new File(System.getProperty("catalina.base"), "conf");
461         Container container = context;
462         Container host = null;
463         Container engine = null;
464         while (container != null) {
465             if (container instanceof Host)
466                 host = container;
467             if (container instanceof Engine)
468                 engine = container;
469             container = container.getParent();
470         }
471         if (engine != null) {
472             configBase = new File(configBase, engine.getName());
473         }
474         if (host != null) {
475             configBase = new File(configBase, host.getName());
476         }
477         // Note: The directory must exist for this to work.
478 
479         // Log debugging messages as necessary
480         if (debug >= 1) {
481             log("init: Associated with Engine '" +
482                 engine.getName() + "'");
483             if (global != null) {
484                 log("init: Global resources are available");
485             }
486         }
487 
488     }
489 
490 
491 
492     // -------------------------------------------------------- Private Methods
493 
494 
495     /**
496      * Render a list of the currently active vhosts.
497      *
498      * @param writer Writer to render to
499      */
500     protected void vhosts(PrintWriter writer) {
501 
502         if (debug >= 1)
503             log("list: Listing virtual hosts for engine '" +
504                 engine.getName() + "'");
505 
506         writer.println(sm.getString("managerServlet.vhosts",
507                                     engine.getName()));
508         
509         Container hosts[] = engine.findChildren();
510         for (int i = 0; i < hosts.length; i++) {            
511             writer.println(sm.getString("managerServlet.hostitem",
512                                         hosts[i].getName()));            
513         }
514         
515     }
516     
517     /**
518      * Store server configuration.
519      * 
520      * @param vhost Virtual host to be listed
521      * @param path Optional context path to save
522      */
523     protected synchronized void save(PrintWriter writer, String vhost, String path) {
524 
525         Server server = ServerFactory.getServer();
526 
527         if (!(server instanceof StandardServer)) {
528             writer.println(sm.getString("managerServlet.saveFail", server));
529             return;
530         }
531 
532         if(vhost == null || vhost.length() == 0) {
533             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
534             return;
535         }        
536 
537         Host host = (Host) engine.findChild(vhost);
538         if (host == null) {
539             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
540             return;                
541         }
542 
543         if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
544             try {
545                 ((StandardServer) server).storeConfig();
546                 writer.println(sm.getString("managerServlet.saved"));
547             } catch (Exception e) {
548                 log("managerServlet.storeConfig", e);
549                 writer.println(sm.getString("managerServlet.exception",
550                                             e.toString()));
551                 return;
552             }
553         } else {
554             String contextPath = path;
555             if (path.equals("/")) {
556                 contextPath = "";
557             }
558             Context context = (Context) host.findChild(contextPath);
559             if (context == null) {
560                 writer.println(sm.getString("managerServlet.noContext", path));
561                 return;
562             }
563             try {
564                 ((StandardServer) server).storeContext(context);
565                 writer.println(sm.getString("managerServlet.savedContext", 
566                                path));
567             } catch (Exception e) {
568                 log("managerServlet.save[" + path + "]", e);
569                 writer.println(sm.getString("managerServlet.exception",
570                                             e.toString()));
571                 return;
572             }
573         }
574 
575     }
576 
577 
578     /**
579      * Deploy a web application archive (included in the current request)
580      * at the specified context path.
581      *
582      * @param writer Writer to render results to
583      * @param vhost Virtual host to be listed
584      * @param path Context path of the application to be installed
585      * @param tag Tag to be associated with the webapp
586      * @param request Servlet request we are processing
587      */
588     protected synchronized void deploy
589         (PrintWriter writer, String vhost, String path,
590          String tag, boolean update, HttpServletRequest request) {
591 
592         if (debug >= 1) {
593             log("deploy: Deploying web application at '" + vhost + ":" + path + "'");
594         }
595 
596         if(vhost == null || vhost.length() == 0) {
597             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
598             return;
599         }        
600 
601         Host host = (Host) engine.findChild(vhost);
602         if (host == null) {
603             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
604             return;                
605         }
606 
607         // Validate the requested context path
608         if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
609             writer.println(sm.getString("managerServlet.invalidPath", path));
610             return;
611         }
612         String displayPath = path;
613         if( path.equals("/") )
614             path = "";
615         String basename = getDocBase(path);
616 
617         // Check if app already exists, or undeploy it if updating
618         Context context = (Context) host.findChild(path);
619         if (update) {
620             if (context != null) {
621                 undeploy(writer, vhost, displayPath);
622             }
623             context = (Context) host.findChild(path);
624         }
625         if (context != null) {
626             writer.println
627                 (sm.getString("managerServlet.alreadyContext",
628                               displayPath));
629             return;
630         }
631 
632         // Calculate the base path
633         File deployedPath = getDeployed(context);
634         if (tag != null) {
635             deployedPath = new File(versioned, tag);
636             deployedPath.mkdirs();
637         }
638 
639         // Upload the web application archive to a local WAR file
640         File localWar = new File(deployedPath, basename + ".war");
641         if (debug >= 2) {
642             log("Uploading WAR file to " + localWar);
643         }
644 
645         // Copy WAR to appBase
646         try {
647             if (!isServiced(host, path)) {
648                 addServiced(host, path);
649                 try {
650                     // Upload WAR
651                     uploadWar(request, localWar);
652                     // Copy WAR and XML to the host app base if needed
653                     if (tag != null) {
654                         deployedPath = getDeployed(context);
655                         File localWarCopy = new File(deployedPath, basename + ".war");
656                         copy(localWar, localWarCopy);
657                         localWar = localWarCopy;
658                         copy(localWar, new File(getAppBase(host), basename + ".war"));
659                     }
660                     // Perform new deployment
661                     check(host, path);
662                 } finally {
663                     removeServiced(host, path);
664                 }
665             }
666         } catch (Exception e) {
667             log("managerServlet.check[" + displayPath + "]", e);
668             writer.println(sm.getString("managerServlet.exception",
669                                         e.toString()));
670             return;
671         }
672         
673         context = (Context) host.findChild(path);
674         if (context != null && context.getConfigured()) {
675             writer.println(sm.getString("managerServlet.deployed", displayPath));
676         } else {
677             // Something failed
678             writer.println(sm.getString("managerServlet.deployFailed", displayPath));
679         }
680         
681     }
682 
683 
684     /**
685      * Install an application for the specified path from the specified
686      * web application archive.
687      *
688      * @param writer Writer to render results to
689      * @param vhost Virtual host to be listed
690      * @param tag Revision tag to deploy from
691      * @param path Context path of the application to be installed
692      */
693     protected void deploy(PrintWriter writer, String vhost, String path, String tag) {
694 
695         if(vhost == null || vhost.length() == 0) {
696             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
697             return;
698         }        
699 
700         Host host = (Host) engine.findChild(vhost);
701         if (host == null) {
702             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
703             return;                
704         }
705 
706         // Validate the requested context path
707         if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
708             writer.println(sm.getString("managerServlet.invalidPath", path));
709             return;
710         }
711         String displayPath = path;
712         if( path.equals("/") )
713             path = "";
714 
715         // Calculate the base path
716         File deployedPath = versioned;
717         if (tag != null) {
718             deployedPath = new File(deployedPath, tag);
719         }
720 
721         // Find the local WAR file
722         File localWar = new File(deployedPath, getDocBase(path) + ".war");
723         // Find the local context deployment file (if any)
724         File localXml = new File(configBase, getConfigFile(path) + ".xml");
725 
726         // Check if app already exists, or undeploy it if updating
727         Context context = (Context) host.findChild(path);
728         if (context != null) {
729             undeploy(writer, vhost, displayPath);
730         }
731 
732         // Copy WAR to appBase
733         try {
734             if (!isServiced(host, path)) {
735                 addServiced(host, path);
736                 try {
737                     copy(localWar, new File(getAppBase(host), getDocBase(path) + ".war"));
738                     // Perform new deployment
739                     check(host, path);
740                 } finally {
741                     removeServiced(host, path);
742                 }
743             }
744         } catch (Exception e) {
745             log("managerServlet.check[" + displayPath + "]", e);
746             writer.println(sm.getString("managerServlet.exception",
747                                         e.toString()));
748             return;
749         }
750         
751         context = (Context) host.findChild(path);
752         if (context != null && context.getConfigured()) {
753             writer.println(sm.getString("managerServlet.deployed", displayPath));
754         } else {
755             // Something failed
756             writer.println(sm.getString("managerServlet.deployFailed", displayPath));
757         }
758         
759     }
760 
761 
762     /**
763      * Install an application for the specified path from the specified
764      * web application archive.
765      *
766      * @param writer Writer to render results to
767      * @param vhost Virtual host to be listed
768      * @param config URL of the context configuration file to be installed
769      * @param path Context path of the application to be installed
770      * @param war URL of the web application archive to be installed
771      * @param update true to override any existing webapp on the path
772      */
773     protected void deploy(PrintWriter writer, String vhost, String config,
774                           String path, String war, boolean update) {
775 
776         if(vhost == null || vhost.length() == 0) {
777             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
778             return;
779         }        
780 
781         Host host = (Host) engine.findChild(vhost);
782         if (host == null) {
783             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
784             return;                
785         }
786 
787         if (config != null && config.length() == 0) {
788             config = null;
789         }
790         if (war != null && war.length() == 0) {
791             war = null;
792         }
793         
794         if (debug >= 1) {
795             if (config != null && config.length() > 0) {
796                 if (war != null) {
797                     log("install: Installing context configuration at '" +
798                             config + "' from '" + war + "'");
799                 } else {
800                     log("install: Installing context configuration at '" +
801                             config + "'");
802                 }
803             } else {
804                 if (path != null && path.length() > 0) {
805                     log("install: Installing web application at '" + path +
806                             "' from '" + war + "'");
807                 } else {
808                     log("install: Installing web application from '" + war + "'");
809                 }
810             }
811         }
812         
813         if (path == null || path.length() == 0 || !path.startsWith("/")) {
814             writer.println(sm.getString("managerServlet.invalidPath",
815                                         RequestUtil.filter(path)));
816             return;
817         }
818         String displayPath = path;
819         if("/".equals(path)) {
820             path = "";
821         }
822         
823         // Check if app already exists, or undeploy it if updating
824         Context context = (Context) host.findChild(path);
825         if (update) {
826             if (context != null) {
827                 undeploy(writer, vhost, displayPath);
828             }
829             context = (Context) host.findChild(path);
830         }
831         if (context != null) {
832             writer.println
833             (sm.getString("managerServlet.alreadyContext",
834                     displayPath));
835             return;
836         }
837         
838         if (config != null && (config.startsWith("file:"))) {
839             config = config.substring("file:".length());
840         }
841         if (war != null && (war.startsWith("file:"))) {
842             war = war.substring("file:".length());
843         }
844         
845         try {
846             if (!isServiced(host, path)) {
847                 addServiced(host, path);
848                 try {
849                     if (config != null) {
850                         copy(new File(config), 
851                                 new File(configBase, getConfigFile(path) + ".xml"));
852                     }
853                     if (war != null) {
854                         if (war.endsWith(".war")) {
855                             copy(new File(war), 
856                                     new File(getAppBase(host), getDocBase(path) + ".war"));
857                         } else {
858                             copy(new File(war), 
859                                     new File(getAppBase(host), getDocBase(path)));
860                         }
861                     }
862                     // Perform new deployment
863                     check(host, path);
864                 } finally {
865                     removeServiced(host, path);
866                 }
867             }
868             context = (Context) host.findChild(path);
869             if (context != null && context.getConfigured()) {
870                 writer.println(sm.getString("managerServlet.deployed", displayPath));
871             } else {
872                 // Something failed
873                 writer.println(sm.getString("managerServlet.deployFailed", displayPath));
874             }
875         } catch (Throwable t) {
876             log("ManagerServlet.install[" + displayPath + "]", t);
877             writer.println(sm.getString("managerServlet.exception",
878                     t.toString()));
879         }
880         
881     }
882 
883 
884     /**
885      * Render a list of the currently active Contexts in our virtual host.
886      *
887      * @param writer Writer to render to
888      * @param vhost Virtual host to be listed
889      */
890     protected void list(PrintWriter writer, String vhost) {
891 
892         if (debug >= 1)
893             log("list: Listing contexts for virtual host '" +
894                 vhost + "'");
895 
896         if(vhost == null || vhost.length() == 0) {
897             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
898             return;
899         }        
900 
901         Host host = (Host) engine.findChild(vhost);
902         if (host == null) {
903             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
904             return;                
905         }
906 
907         writer.println(sm.getString("managerServlet.listed",
908                                     host.getName()));
909         Container[] contexts = host.findChildren();
910         for (int i = 0; i < contexts.length; i++) {
911             Context context = (Context) contexts[i];
912             String displayPath = context.getPath();
913             if( displayPath.equals("") )
914                 displayPath = "/";
915             if (context != null ) {
916                 if (context.getAvailable()) {
917                     writer.println(sm.getString("managerServlet.listitem",
918                                                 displayPath,
919                                                 "running",
920                                       "" + context.getManager().findSessions().length,
921                                                 context.getDocBase()));
922                 } else {
923                     writer.println(sm.getString("managerServlet.listitem",
924                                                 displayPath,
925                                                 "stopped",
926                                                 "0",
927                                                 context.getDocBase()));
928                 }
929             }
930         }
931     }
932 
933 
934     /**
935      * Reload the web application at the specified context path.
936      *
937      * @param writer Writer to render to
938      * @param vhost Virtual host to be listed
939      * @param path Context path of the application to be restarted
940      */
941     protected void reload(PrintWriter writer, String vhost, String path) {
942 
943         if (debug >= 1)
944             log("restart: Reloading web application at '" + vhost + ":" + path + "'");
945 
946         if(vhost == null || vhost.length() == 0) {
947             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
948             return;
949         }        
950 
951         Host host = (Host) engine.findChild(vhost);
952         if (host == null) {
953             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
954             return;                
955         }
956 
957         if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
958             writer.println(sm.getString("managerServlet.invalidPath",
959                                         RequestUtil.filter(path)));
960             return;
961         }
962         String displayPath = path;
963         if( path.equals("/") )
964             path = "";
965 
966         try {
967             Context context = (Context) host.findChild(path);
968             if (context == null) {
969                 writer.println(sm.getString
970                                ("managerServlet.noContext",
971                                    RequestUtil.filter(displayPath)));
972                 return;
973             }
974             // It isn't possible for the manager to reload itself
975             if (context.getPath().equals(this.context.getPath())) {
976                 writer.println(sm.getString("managerServlet.noSelf"));
977                 return;
978             }
979             context.reload();
980             writer.println
981                 (sm.getString("managerServlet.reloaded", displayPath));
982         } catch (Throwable t) {
983             log("ManagerServlet.reload[" + displayPath + "]", t);
984             writer.println(sm.getString("managerServlet.exception",
985                                         t.toString()));
986         }
987 
988     }
989 
990 
991     /**
992      * Render a list of available global JNDI resources.
993      *
994      * @param type Fully qualified class name of the resource type of interest,
995      *  or <code>null</code> to list resources of all types
996      */
997     protected void resources(PrintWriter writer, String type) {
998 
999         if (debug >= 1) {
1000             if (type != null) {
1001                 log("resources:  Listing resources of type " + type);
1002             } else {
1003                 log("resources:  Listing resources of all types");
1004             }
1005         }
1006 
1007         // Is the global JNDI resources context available?
1008         if (global == null) {
1009             writer.println(sm.getString("managerServlet.noGlobal"));
1010             return;
1011         }
1012 
1013         // Enumerate the global JNDI resources of the requested type
1014         if (type != null) {
1015             writer.println(sm.getString("managerServlet.resourcesType",
1016                                         type));
1017         } else {
1018             writer.println(sm.getString("managerServlet.resourcesAll"));
1019         }
1020 
1021         Class clazz = null;
1022         try {
1023             if (type != null) {
1024                 clazz = Class.forName(type);
1025             }
1026         } catch (Throwable t) {
1027             log("ManagerServlet.resources[" + type + "]", t);
1028             writer.println(sm.getString("managerServlet.exception",
1029                                         t.toString()));
1030             return;
1031         }
1032 
1033         printResources(writer, "", global, type, clazz);
1034 
1035     }
1036 
1037 
1038     /**
1039      * List the resources of the given context.
1040      */
1041     protected void printResources(PrintWriter writer, String prefix,
1042                                   javax.naming.Context namingContext,
1043                                   String type, Class clazz) {
1044 
1045         try {
1046             NamingEnumeration items = namingContext.listBindings("");
1047             while (items.hasMore()) {
1048                 Binding item = (Binding) items.next();
1049                 if (item.getObject() instanceof javax.naming.Context) {
1050                     printResources
1051                         (writer, prefix + item.getName() + "/",
1052                          (javax.naming.Context) item.getObject(), type, clazz);
1053                 } else {
1054                     if ((clazz != null) &&
1055                         (!(clazz.isInstance(item.getObject())))) {
1056                         continue;
1057                     }
1058                     writer.print(prefix + item.getName());
1059                     writer.print(':');
1060                     writer.print(item.getClassName());
1061                     // Do we want a description if available?
1062                     writer.println();
1063                 }
1064             }
1065         } catch (Throwable t) {
1066             log("ManagerServlet.resources[" + type + "]", t);
1067             writer.println(sm.getString("managerServlet.exception",
1068                                         t.toString()));
1069         }
1070 
1071     }
1072 
1073 
1074     /**
1075      * Render a list of security role names (and corresponding descriptions)
1076      * from the <code>org.apache.catalina.UserDatabase</code> resource that is
1077      * connected to the <code>users</code> resource reference.  Typically, this
1078      * will be the global user database, but can be adjusted if you have
1079      * different user databases for different virtual hosts.
1080      *
1081      * @param writer Writer to render to
1082      */
1083     protected void roles(PrintWriter writer) {
1084 
1085         if (debug >= 1) {
1086             log("roles:  List security roles from user database");
1087         }
1088 
1089         // Look up the UserDatabase instance we should use
1090         UserDatabase database = null;
1091         try {
1092             InitialContext ic = new InitialContext();
1093             database = (UserDatabase) ic.lookup("java:comp/env/users");
1094         } catch (NamingException e) {
1095             writer.println(sm.getString("managerServlet.userDatabaseError"));
1096             log("java:comp/env/users", e);
1097             return;
1098         }
1099         if (database == null) {
1100             writer.println(sm.getString("managerServlet.userDatabaseMissing"));
1101             return;
1102         }
1103 
1104         // Enumerate the available roles
1105         writer.println(sm.getString("managerServlet.rolesList"));
1106         Iterator roles = database.getRoles();
1107         if (roles != null) {
1108             while (roles.hasNext()) {
1109                 Role role = (Role) roles.next();
1110                 writer.print(role.getRolename());
1111                 writer.print(':');
1112                 if (role.getDescription() != null) {
1113                     writer.print(role.getDescription());
1114                 }
1115                 writer.println();
1116             }
1117         }
1118 
1119 
1120     }
1121 
1122 
1123     /**
1124      * Writes System OS and JVM properties.
1125      * @param writer Writer to render to
1126      */
1127     protected void serverinfo(PrintWriter writer) {
1128         if (debug >= 1)
1129             log("serverinfo");
1130         try {
1131             StringBuffer props = new StringBuffer();
1132             props.append("OK - Server info");
1133             props.append("\nTomcat Version: ");
1134             props.append(ServerInfo.getServerInfo());
1135             props.append("\nOS Name: ");
1136             props.append(System.getProperty("os.name"));
1137             props.append("\nOS Version: ");
1138             props.append(System.getProperty("os.version"));
1139             props.append("\nOS Architecture: ");
1140             props.append(System.getProperty("os.arch"));
1141             props.append("\nJVM Version: ");
1142             props.append(System.getProperty("java.runtime.version"));
1143             props.append("\nJVM Vendor: ");
1144             props.append(System.getProperty("java.vm.vendor"));
1145             writer.println(props.toString());
1146         } catch (Throwable t) {
1147             getServletContext().log("ManagerServlet.serverinfo",t);
1148             writer.println(sm.getString("managerServlet.exception",
1149                                         t.toString()));
1150         }
1151     }
1152 
1153     /**
1154      * Session information for the web application at the specified context path.
1155      * Displays a profile of session MaxInactiveInterval timeouts listing number
1156      * of sessions for each 10 minute timeout interval up to 10 hours.
1157      *
1158      * @param writer Writer to render to
1159      * @param vhost Virtual host to be listed
1160      * @param path Context path of the application to list session information for
1161      */
1162     protected void sessions(PrintWriter writer, String vhost, String path) {
1163 
1164         if (debug >= 1)
1165             log("sessions: Session information for web application at '" + vhost + ":" + path + "'");
1166 
1167         if(vhost == null || vhost.length() == 0) {
1168             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1169             return;
1170         }        
1171 
1172         Host host = (Host) engine.findChild(vhost);
1173         if (host == null) {
1174             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1175             return;                
1176         }
1177 
1178         if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
1179             writer.println(sm.getString("managerServlet.invalidPath",
1180                                         RequestUtil.filter(path)));
1181             return;
1182         }
1183         String displayPath = path;
1184         if( path.equals("/") )
1185             path = "";
1186         try {
1187             Context context = (Context) host.findChild(path);
1188             if (context == null) {
1189                 writer.println(sm.getString("managerServlet.noContext",
1190                                             RequestUtil.filter(displayPath)));
1191                 return;
1192             }
1193             writer.println(sm.getString("managerServlet.sessions", displayPath));
1194             writer.println(sm.getString("managerServlet.sessiondefaultmax",
1195                                 "" + context.getManager().getMaxInactiveInterval()/60));
1196             Session [] sessions = context.getManager().findSessions();
1197             int [] timeout = new int[60];
1198             int notimeout = 0;
1199             for (int i = 0; i < sessions.length; i++) {
1200                 int time = sessions[i].getMaxInactiveInterval()/(10*60);
1201                 if (time < 0)
1202                     notimeout++;
1203                 else if (time >= timeout.length)
1204                     timeout[timeout.length-1]++;
1205                 else
1206                     timeout[time]++;
1207             }
1208             if (timeout[0] > 0)
1209                 writer.println(sm.getString("managerServlet.sessiontimeout",
1210                                             "<10", "" + timeout[0]));
1211             for (int i = 1; i < timeout.length-1; i++) {
1212                 if (timeout[i] > 0)
1213                     writer.println(sm.getString("managerServlet.sessiontimeout",
1214                                      "" + (i)*10 + " - <" + (i+1)*10,
1215                                                 "" + timeout[i]));
1216             }
1217             if (timeout[timeout.length-1] > 0)
1218                 writer.println(sm.getString("managerServlet.sessiontimeout",
1219                                             ">=" + timeout.length*10,
1220                                             "" + timeout[timeout.length-1]));
1221             if (notimeout > 0)
1222                 writer.println(sm.getString("managerServlet.sessiontimeout",
1223                                             "unlimited","" + notimeout));
1224         } catch (Throwable t) {
1225             log("ManagerServlet.sessions[" + displayPath + "]", t);
1226             writer.println(sm.getString("managerServlet.exception",
1227                                         t.toString()));
1228         }
1229 
1230     }
1231 
1232 
1233     /**
1234      * Start the web application at the specified context path.
1235      *
1236      * @param writer Writer to render to
1237      * @param vhost Virtual host to be listed
1238      * @param path Context path of the application to be started
1239      */
1240     protected void start(PrintWriter writer, String vhost, String path) {
1241 
1242         if (debug >= 1)
1243             log("start: Starting web application at '" + vhost + ":" + path + "'");
1244 
1245         if(vhost == null || vhost.length() == 0) {
1246             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1247             return;
1248         }        
1249 
1250         Host host = (Host) engine.findChild(vhost);
1251         if (host == null) {
1252             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1253             return;                
1254         }
1255 
1256         if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
1257             writer.println(sm.getString("managerServlet.invalidPath",
1258                                         RequestUtil.filter(path)));
1259             return;
1260         }
1261         String displayPath = path;
1262         if( path.equals("/") )
1263             path = "";
1264 
1265         try {
1266             Context context = (Context) host.findChild(path);
1267             if (context == null) {
1268                 writer.println(sm.getString("managerServlet.noContext", 
1269                                             RequestUtil.filter(displayPath)));
1270                 return;
1271             }
1272             ((Lifecycle) context).start();
1273             if (context.getAvailable())
1274                 writer.println
1275                     (sm.getString("managerServlet.started", displayPath));
1276             else
1277                 writer.println
1278                     (sm.getString("managerServlet.startFailed", displayPath));
1279         } catch (Throwable t) {
1280             getServletContext().log
1281                 (sm.getString("managerServlet.startFailed", displayPath), t);
1282             writer.println
1283                 (sm.getString("managerServlet.startFailed", displayPath));
1284             writer.println(sm.getString("managerServlet.exception",
1285                                         t.toString()));
1286         }
1287 
1288     }
1289 
1290 
1291     /**
1292      * Stop the web application at the specified context path.
1293      *
1294      * @param writer Writer to render to
1295      * @param vhost Virtual host to be listed
1296      * @param path Context path of the application to be stopped
1297      */
1298     protected void stop(PrintWriter writer, String vhost, String path) {
1299 
1300         if (debug >= 1)
1301             log("stop: Stopping web application at '" + vhost + ":" + path + "'");
1302 
1303         if(vhost == null || vhost.length() == 0) {
1304             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1305             return;
1306         }        
1307 
1308         Host host = (Host) engine.findChild(vhost);
1309         if (host == null) {
1310             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1311             return;                
1312         }
1313 
1314         if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
1315             writer.println(sm.getString("managerServlet.invalidPath",
1316                                         RequestUtil.filter(path)));
1317             return;
1318         }
1319         String displayPath = path;
1320         if( path.equals("/") )
1321             path = "";
1322 
1323         try {
1324             Context context = (Context) host.findChild(path);
1325             if (context == null) {
1326                 writer.println(sm.getString("managerServlet.noContext", 
1327                                             RequestUtil.filter(displayPath)));
1328                 return;
1329             }
1330             // It isn't possible for the manager to stop itself
1331             if (context.getPath().equals(this.context.getPath())) {
1332                 writer.println(sm.getString("managerServlet.noSelf"));
1333                 return;
1334             }
1335             ((Lifecycle) context).stop();
1336             writer.println(sm.getString("managerServlet.stopped", displayPath));
1337         } catch (Throwable t) {
1338             log("ManagerServlet.stop[" + displayPath + "]", t);
1339             writer.println(sm.getString("managerServlet.exception",
1340                                         t.toString()));
1341         }
1342 
1343     }
1344 
1345 
1346     /**
1347      * Undeploy the web application at the specified context path.
1348      *
1349      * @param writer Writer to render to
1350      * @param vhost Virtual host to be listed
1351      * @param path Context path of the application to be removed
1352      */
1353     protected void undeploy(PrintWriter writer, String vhost, String path) {
1354 
1355         if (debug >= 1)
1356             log("undeploy: Undeploying web application at '" + vhost + ":" + path + "'");
1357 
1358         if(vhost == null || vhost.length() == 0) {
1359             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1360             return;
1361         }        
1362 
1363         Host host = (Host) engine.findChild(vhost);
1364         if (host == null) {
1365             writer.println(sm.getString("managerServlet.invalidVirtualHost", vhost));
1366             return;                
1367         }
1368 
1369         if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
1370             writer.println(sm.getString("managerServlet.invalidPath",
1371                                         RequestUtil.filter(path)));
1372             return;
1373         }
1374         String displayPath = path;
1375         if( path.equals("/") )
1376             path = "";
1377 
1378         try {
1379 
1380             // Validate the Context of the specified application
1381             Context context = (Context) host.findChild(path);
1382             if (context == null) {
1383                 writer.println(sm.getString("managerServlet.noContext",
1384                                             RequestUtil.filter(displayPath)));
1385                 return;
1386             }
1387 
1388             // Identify the appBase of the owning Host of this Context (if any)
1389             String appBase = null;
1390             File appBaseDir = null;
1391             if (context.getParent() instanceof Host) {
1392                 appBase = ((Host) context.getParent()).getAppBase();
1393                 appBaseDir = new File(appBase);
1394                 if (!appBaseDir.isAbsolute()) {
1395                     appBaseDir = new File(System.getProperty("catalina.base"),
1396                                           appBase);
1397                 }
1398             }
1399 
1400             if (!isServiced(host, path)) {
1401                 addServiced(host, path);
1402                 try {
1403                     // Try to stop the context first to be nicer
1404                     ((Lifecycle) context).stop();
1405                 } catch (Throwable t) {
1406                     // Ignore
1407                 }
1408                 try {
1409                     File war = new File(getAppBase(host), getDocBase(path) + ".war");
1410                     File dir = new File(getAppBase(host), getDocBase(path));
1411                     File xml = new File(configBase, getConfigFile(path) + ".xml");
1412                     if (war.exists()) {
1413                         war.delete();
1414                     } else if (dir.exists()) {
1415                         undeployDir(dir);
1416                     } else {
1417                         xml.delete();
1418                     }
1419                     // Perform new deployment
1420                     check(host, path);
1421                 } finally {
1422                     removeServiced(host, path);
1423                 }
1424             }
1425             writer.println(sm.getString("managerServlet.undeployed",
1426                                         displayPath));
1427         } catch (Throwable t) {
1428             log("ManagerServlet.undeploy[" + displayPath + "]", t);
1429             writer.println(sm.getString("managerServlet.exception",
1430                                         t.toString()));
1431         }
1432 
1433     }
1434 
1435 
1436     // -------------------------------------------------------- Support Methods
1437 
1438 
1439     /**
1440      * Given a context path, get the config file name.
1441      */
1442     protected String getConfigFile(String path) {
1443         String basename = null;
1444         if (path.equals("")) {
1445             basename = "ROOT";
1446         } else {
1447             basename = path.substring(1).replace('/', '#');
1448         }
1449         return (basename);
1450     }
1451 
1452 
1453     /**
1454      * Given a context path, get the config file name.
1455      */
1456     protected String getDocBase(String path) {
1457         String basename = null;
1458         if (path.equals("")) {
1459             basename = "ROOT";
1460         } else {
1461             basename = path.substring(1);
1462         }
1463         return (basename);
1464     }
1465 
1466     
1467     /**
1468      * Return a File object representing the "application root" directory
1469      * for our associated Host.
1470      */
1471     protected File getAppBase(Host host) {
1472 
1473         if (appBase != null) {
1474             return appBase;
1475         }
1476 
1477         File file = new File(host.getAppBase());
1478         if (!file.isAbsolute())
1479             file = new File(System.getProperty("catalina.base"),
1480                             host.getAppBase());
1481         try {
1482             appBase = file.getCanonicalFile();
1483         } catch (IOException e) {
1484             appBase = file;
1485         }
1486         return (appBase);
1487 
1488     }
1489 
1490 
1491     /**
1492      * Invoke the check method on the deployer.
1493      */
1494     protected void check(Host host, String name) 
1495         throws Exception {
1496         String[] params = { name };
1497         String[] signature = { "java.lang.String" };
1498         mBeanServer.invoke(getObjectName(host), "check", params, signature);
1499     }
1500     
1501 
1502     /**
1503      * Invoke the check method on the deployer.
1504      */
1505     protected boolean isServiced(Host host, String name) 
1506         throws Exception {
1507         String[] params = { name };
1508         String[] signature = { "java.lang.String" };
1509         Boolean result = 
1510             (Boolean) mBeanServer.invoke(getObjectName(host), "isServiced", params, signature);
1511         return result.booleanValue();
1512     }
1513     
1514 
1515     /**
1516      * Invoke the check method on the deployer.
1517      */
1518     protected void addServiced(Host host, String name) 
1519         throws Exception {
1520         String[] params = { name };
1521         String[] signature = { "java.lang.String" };
1522         mBeanServer.invoke(getObjectName(host), "addServiced", params, signature);
1523     }
1524     
1525 
1526     /**
1527      * Invoke the check method on the deployer.
1528      */
1529     protected void removeServiced(Host host, String name) 
1530         throws Exception {
1531         String[] params = { name };
1532         String[] signature = { "java.lang.String" };
1533         mBeanServer.invoke(getObjectName(host), "removeServiced", params, signature);
1534     }
1535     
1536 
1537     /**
1538      * Delete the specified directory, including all of its contents and
1539      * subdirectories recursively.
1540      *
1541      * @param dir File object representing the directory to be deleted
1542      */
1543     protected void undeployDir(File dir) {
1544 
1545         String files[] = dir.list();
1546         if (files == null) {
1547             files = new String[0];
1548         }
1549         for (int i = 0; i < files.length; i++) {
1550             File file = new File(dir, files[i]);
1551             if (file.isDirectory()) {
1552                 undeployDir(file);
1553             } else {
1554                 file.delete();
1555             }
1556         }
1557         dir.delete();
1558 
1559     }
1560 
1561 
1562     /**
1563      * Upload the WAR file included in this request, and store it at the
1564      * specified file location.
1565      *
1566      * @param request The servlet request we are processing
1567      * @param war The file into which we should store the uploaded WAR
1568      *
1569      * @exception IOException if an I/O error occurs during processing
1570      */
1571     protected void uploadWar(HttpServletRequest request, File war)
1572         throws IOException {
1573 
1574         war.delete();
1575         ServletInputStream istream = null;
1576         BufferedOutputStream ostream = null;
1577         try {
1578             istream = request.getInputStream();
1579             ostream =
1580                 new BufferedOutputStream(new FileOutputStream(war), 1024);
1581             byte buffer[] = new byte[1024];
1582             while (true) {
1583                 int n = istream.read(buffer);
1584                 if (n < 0) {
1585                     break;
1586                 }
1587                 ostream.write(buffer, 0, n);
1588             }
1589             ostream.flush();
1590             ostream.close();
1591             ostream = null;
1592             istream.close();
1593             istream = null;
1594         } catch (IOException e) {
1595             war.delete();
1596             throw e;
1597         } finally {
1598             if (ostream != null) {
1599                 try {
1600                     ostream.close();
1601                 } catch (Throwable t) {
1602                     ;
1603                 }
1604                 ostream = null;
1605             }
1606             if (istream != null) {
1607                 try {
1608                     istream.close();
1609                 } catch (Throwable t) {
1610                     ;
1611                 }
1612                 istream = null;
1613             }
1614         }
1615 
1616     }
1617 
1618 
1619     /**
1620      * Copy the specified file or directory to the destination.
1621      *
1622      * @param src File object representing the source
1623      * @param dest File object representing the destination
1624      */
1625     public static boolean copy(File src, File dest) {
1626         boolean result = false;
1627         try {
1628             if( src != null &&
1629                     !src.getCanonicalPath().equals(dest.getCanonicalPath()) ) {
1630                 result = copyInternal(src, dest, new byte[4096]);
1631             }
1632         } catch (IOException e) {
1633             e.printStackTrace();
1634         }
1635         return result;
1636     }
1637 
1638     
1639     /**
1640      * Copy the specified file or directory to the destination.
1641      *
1642      * @param src File object representing the source
1643      * @param dest File object representing the destination
1644      */
1645     public static boolean copyInternal(File src, File dest, byte[] buf) {
1646         
1647         boolean result = true;
1648         
1649         String files[] = null;
1650         if (src.isDirectory()) {
1651             files = src.list();
1652             result = dest.mkdir();
1653         } else {
1654             files = new String[1];
1655             files[0] = "";
1656         }
1657         if (files == null) {
1658             files = new String[0];
1659         }
1660         for (int i = 0; (i < files.length) && result; i++) {
1661             File fileSrc = new File(src, files[i]);
1662             File fileDest = new File(dest, files[i]);
1663             if (fileSrc.isDirectory()) {
1664                 result = copyInternal(fileSrc, fileDest, buf);
1665             } else {
1666                 FileInputStream is = null;
1667                 FileOutputStream os = null;
1668                 try {
1669                     is = new FileInputStream(fileSrc);
1670                     os = new FileOutputStream(fileDest);
1671                     int len = 0;
1672                     while (true) {
1673                         len = is.read(buf);
1674                         if (len == -1)
1675                             break;
1676                         os.write(buf, 0, len);
1677                     }
1678                 } catch (IOException e) {
1679                     e.printStackTrace();
1680                     result = false;
1681                 } finally {
1682                     if (is != null) {
1683                         try {
1684                             is.close();
1685                         } catch (IOException e) {
1686                         }
1687                     }
1688                     if (os != null) {
1689                         try {
1690                             os.close();
1691                         } catch (IOException e) {
1692                         }
1693                     }
1694                 }
1695             }
1696         }
1697         return result;
1698         
1699     }
1700 
1701 
1702     /**
1703      * Identify the appBase of the Host of Context
1704      * (if any)
1705      * 
1706      * @param context context to obtain appBase
1707      * 
1708      * @return File representing appBase directory 
1709      */
1710     private File getDeployed(Context context) {
1711         
1712         File deployed = null;
1713         
1714         String appBase = ((Host) context.getParent()).getAppBase();
1715         deployed = new File(appBase);
1716         if (!deployed.isAbsolute()) {
1717             deployed = new File(System.getProperty("catalina.base"),
1718                                 appBase);
1719         }
1720         
1721         return deployed;
1722         
1723     }
1724     
1725     
1726 
1727     /**
1728      * Identify the associated deployer ObjectName of the Host of Context
1729      * (if any)
1730      * 
1731      * @param host host to obtain associated deployer ObjectName
1732      * 
1733      * @return ObjectName associated deployer ObjectName 
1734      */
1735     private ObjectName getObjectName(Host host) {
1736         
1737         ObjectName oname = null;
1738         try {
1739             oname = new ObjectName(engine.getName() 
1740               + ":type=Deployer,host=" + host.getName());
1741         } catch (Exception e) {
1742             // ?
1743         }
1744         
1745         return oname;
1746         
1747     }
1748     
1749 
1750 }