KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > manager > ManagerServlet


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.manager;
20
21
22 import java.io.BufferedOutputStream JavaDoc;
23 import java.io.File JavaDoc;
24 import java.io.FileInputStream JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.PrintWriter JavaDoc;
28 import java.util.Iterator JavaDoc;
29
30 import javax.management.MBeanServer JavaDoc;
31 import javax.management.ObjectName JavaDoc;
32 import javax.naming.Binding JavaDoc;
33 import javax.naming.InitialContext JavaDoc;
34 import javax.naming.NamingEnumeration JavaDoc;
35 import javax.naming.NamingException JavaDoc;
36 import javax.servlet.ServletException JavaDoc;
37 import javax.servlet.ServletInputStream JavaDoc;
38 import javax.servlet.UnavailableException JavaDoc;
39 import javax.servlet.http.HttpServlet JavaDoc;
40 import javax.servlet.http.HttpServletRequest JavaDoc;
41 import javax.servlet.http.HttpServletResponse JavaDoc;
42
43 import org.apache.catalina.Container;
44 import org.apache.catalina.ContainerServlet;
45 import org.apache.catalina.Context;
46 import org.apache.catalina.Engine;
47 import org.apache.catalina.Globals;
48 import org.apache.catalina.Host;
49 import org.apache.catalina.Lifecycle;
50 import org.apache.catalina.Role;
51 import org.apache.catalina.Server;
52 import org.apache.catalina.ServerFactory;
53 import org.apache.catalina.Session;
54 import org.apache.catalina.UserDatabase;
55 import org.apache.catalina.Wrapper;
56 import org.apache.catalina.core.StandardServer;
57 import org.apache.catalina.util.RequestUtil;
58 import org.apache.catalina.util.ServerInfo;
59 import org.apache.catalina.util.StringManager;
60 import org.apache.tomcat.util.modeler.Registry;
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  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
156  */

157
158 public class ManagerServlet
159     extends HttpServlet JavaDoc implements ContainerServlet {
160
161
162     // ----------------------------------------------------- Instance Variables
163

164
165     /**
166      * Path where context descriptors should be deployed.
167      */

168     protected File JavaDoc configBase = null;
169
170
171     /**
172      * The Context container associated with our web application.
173      */

174     protected Context JavaDoc context = null;
175
176
177     /**
178      * The debugging detail level for this servlet.
179      */

180     protected int debug = 1;
181
182
183     /**
184      * File object representing the directory into which the deploy() command
185      * will store the WAR and context configuration files that have been
186      * uploaded.
187      */

188     protected File JavaDoc deployed = null;
189
190
191     /**
192      * Path used to store revisions of webapps.
193      */

194     protected File JavaDoc versioned = null;
195
196
197     /**
198      * Path used to store context descriptors.
199      */

200     protected File JavaDoc contextDescriptors = null;
201
202
203     /**
204      * The associated host.
205      */

206     protected Host host = null;
207
208     
209     /**
210      * The host appBase.
211      */

212     protected File JavaDoc appBase = null;
213     
214     
215     /**
216      * MBean server.
217      */

218     protected MBeanServer JavaDoc mBeanServer = null;
219
220
221     /**
222      * The associated deployer ObjectName.
223      */

224     protected ObjectName JavaDoc oname = null;
225     
226
227     /**
228      * The global JNDI <code>NamingContext</code> for this server,
229      * if available.
230      */

231     protected javax.naming.Context JavaDoc global = null;
232
233
234     /**
235      * The string manager for this package.
236      */

237     protected static StringManager sm =
238         StringManager.getManager(Constants.Package);
239
240
241     /**
242      * The Wrapper container associated with this servlet.
243      */

244     protected Wrapper wrapper = null;
245
246
247     // ----------------------------------------------- ContainerServlet Methods
248

249
250     /**
251      * Return the Wrapper with which we are associated.
252      */

253     public Wrapper getWrapper() {
254
255         return (this.wrapper);
256
257     }
258
259
260     /**
261      * Set the Wrapper with which we are associated.
262      *
263      * @param wrapper The new wrapper
264      */

265     public void setWrapper(Wrapper wrapper) {
266
267         this.wrapper = wrapper;
268         if (wrapper == null) {
269             context = null;
270             host = null;
271             oname = null;
272         } else {
273             context = (Context JavaDoc) wrapper.getParent();
274             host = (Host) context.getParent();
275             Engine engine = (Engine) host.getParent();
276             try {
277                 oname = new ObjectName JavaDoc(engine.getName()
278                         + ":type=Deployer,host=" + host.getName());
279             } catch (Exception JavaDoc e) {
280                 // ?
281
}
282         }
283
284         // Retrieve the MBean server
285
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
286         
287     }
288
289
290     // --------------------------------------------------------- Public Methods
291

292
293     /**
294      * Finalize this servlet.
295      */

296     public void destroy() {
297
298         ; // No actions necessary
299

300     }
301
302
303     /**
304      * Process a GET request for the specified resource.
305      *
306      * @param request The servlet request we are processing
307      * @param response The servlet response we are creating
308      *
309      * @exception IOException if an input/output error occurs
310      * @exception ServletException if a servlet-specified error occurs
311      */

312     public void doGet(HttpServletRequest JavaDoc request,
313                       HttpServletResponse JavaDoc response)
314         throws IOException JavaDoc, ServletException JavaDoc {
315
316         // Verify that we were not accessed using the invoker servlet
317
if (request.getAttribute(Globals.INVOKED_ATTR) != null)
318             throw new UnavailableException JavaDoc
319                 (sm.getString("managerServlet.cannotInvoke"));
320
321         // Identify the request parameters that we need
322
String JavaDoc command = request.getPathInfo();
323         if (command == null)
324             command = request.getServletPath();
325         String JavaDoc config = request.getParameter("config");
326         String JavaDoc path = request.getParameter("path");
327         String JavaDoc type = request.getParameter("type");
328         String JavaDoc war = request.getParameter("war");
329         String JavaDoc tag = request.getParameter("tag");
330         boolean update = false;
331         if ((request.getParameter("update") != null)
332             && (request.getParameter("update").equals("true"))) {
333             update = true;
334         }
335
336         // Prepare our output writer to generate the response message
337
response.setContentType("text/plain; charset=" + Constants.CHARSET);
338         PrintWriter JavaDoc writer = response.getWriter();
339
340         // Process the requested command (note - "/deploy" is not listed here)
341
if (command == null) {
342             writer.println(sm.getString("managerServlet.noCommand"));
343         } else if (command.equals("/deploy")) {
344             if (war != null || config != null) {
345                 deploy(writer, config, path, war, update);
346             } else {
347                 deploy(writer, path, tag);
348             }
349         } else if (command.equals("/install")) {
350             // Deprecated
351
deploy(writer, config, path, war, false);
352         } else if (command.equals("/list")) {
353             list(writer);
354         } else if (command.equals("/reload")) {
355             reload(writer, path);
356         } else if (command.equals("/remove")) {
357             // Deprecated
358
undeploy(writer, path);
359         } else if (command.equals("/resources")) {
360             resources(writer, type);
361         } else if (command.equals("/roles")) {
362             roles(writer);
363         } else if (command.equals("/save")) {
364             save(writer, path);
365         } else if (command.equals("/serverinfo")) {
366             serverinfo(writer);
367         } else if (command.equals("/sessions")) {
368             sessions(writer, path);
369         } else if (command.equals("/start")) {
370             start(writer, path);
371         } else if (command.equals("/stop")) {
372             stop(writer, path);
373         } else if (command.equals("/undeploy")) {
374             undeploy(writer, path);
375         } else {
376             writer.println(sm.getString("managerServlet.unknownCommand",
377                                         command));
378         }
379
380         // Finish up the response
381
writer.flush();
382         writer.close();
383
384     }
385
386
387     /**
388      * Process a PUT request for the specified resource.
389      *
390      * @param request The servlet request we are processing
391      * @param response The servlet response we are creating
392      *
393      * @exception IOException if an input/output error occurs
394      * @exception ServletException if a servlet-specified error occurs
395      */

396     public void doPut(HttpServletRequest JavaDoc request,
397                       HttpServletResponse JavaDoc response)
398         throws IOException JavaDoc, ServletException JavaDoc {
399
400         // Verify that we were not accessed using the invoker servlet
401
if (request.getAttribute(Globals.INVOKED_ATTR) != null)
402             throw new UnavailableException JavaDoc
403                 (sm.getString("managerServlet.cannotInvoke"));
404
405         // Identify the request parameters that we need
406
String JavaDoc command = request.getPathInfo();
407         if (command == null)
408             command = request.getServletPath();
409         String JavaDoc path = request.getParameter("path");
410         String JavaDoc tag = request.getParameter("tag");
411         boolean update = false;
412         if ((request.getParameter("update") != null)
413             && (request.getParameter("update").equals("true"))) {
414             update = true;
415         }
416
417         // Prepare our output writer to generate the response message
418
response.setContentType("text/plain;charset="+Constants.CHARSET);
419         PrintWriter JavaDoc writer = response.getWriter();
420
421         // Process the requested command
422
if (command == null) {
423             writer.println(sm.getString("managerServlet.noCommand"));
424         } else if (command.equals("/deploy")) {
425             deploy(writer, path, tag, update, request);
426         } else {
427             writer.println(sm.getString("managerServlet.unknownCommand",
428                                         command));
429         }
430
431         // Finish up the response
432
writer.flush();
433         writer.close();
434
435     }
436
437
438     /**
439      * Initialize this servlet.
440      */

441     public void init() throws ServletException JavaDoc {
442
443         // Ensure that our ContainerServlet properties have been set
444
if ((wrapper == null) || (context == null))
445             throw new UnavailableException JavaDoc
446                 (sm.getString("managerServlet.noWrapper"));
447
448         // Verify that we were not accessed using the invoker servlet
449
String JavaDoc servletName = getServletConfig().getServletName();
450         if (servletName == null)
451             servletName = "";
452         if (servletName.startsWith("org.apache.catalina.INVOKER."))
453             throw new UnavailableException JavaDoc
454                 (sm.getString("managerServlet.cannotInvoke"));
455
456         // Set our properties from the initialization parameters
457
String JavaDoc value = null;
458         try {
459             value = getServletConfig().getInitParameter("debug");
460             debug = Integer.parseInt(value);
461         } catch (Throwable JavaDoc t) {
462             ;
463         }
464
465         // Acquire global JNDI resources if available
466
Server JavaDoc server = ServerFactory.getServer();
467         if ((server != null) && (server instanceof StandardServer)) {
468             global = ((StandardServer) server).getGlobalNamingContext();
469         }
470
471         // Calculate the directory into which we will be deploying applications
472
versioned = (File JavaDoc) getServletContext().getAttribute
473             ("javax.servlet.context.tempdir");
474
475         // Identify the appBase of the owning Host of this Context
476
// (if any)
477
String JavaDoc appBase = ((Host) context.getParent()).getAppBase();
478         deployed = new File JavaDoc(appBase);
479         if (!deployed.isAbsolute()) {
480             deployed = new File JavaDoc(System.getProperty("catalina.base"),
481                                 appBase);
482         }
483         configBase = new File JavaDoc(System.getProperty("catalina.base"), "conf");
484         Container container = context;
485         Container host = null;
486         Container engine = null;
487         while (container != null) {
488             if (container instanceof Host)
489                 host = container;
490             if (container instanceof Engine)
491                 engine = container;
492             container = container.getParent();
493         }
494         if (engine != null) {
495             configBase = new File JavaDoc(configBase, engine.getName());
496         }
497         if (host != null) {
498             configBase = new File JavaDoc(configBase, host.getName());
499         }
500         // Note: The directory must exist for this to work.
501

502         // Log debugging messages as necessary
503
if (debug >= 1) {
504             log("init: Associated with Deployer '" +
505                 oname + "'");
506             if (global != null) {
507                 log("init: Global resources are available");
508             }
509         }
510
511     }
512
513
514
515     // -------------------------------------------------------- Private Methods
516

517
518     /**
519      * Store server configuration.
520      *
521      * @param path Optional context path to save
522      */

523     protected synchronized void save(PrintWriter JavaDoc writer, String JavaDoc path) {
524
525         Server JavaDoc server = ServerFactory.getServer();
526
527         if (!(server instanceof StandardServer)) {
528             writer.println(sm.getString("managerServlet.saveFail", server));
529             return;
530         }
531
532         if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
533             try {
534                 ((StandardServer) server).storeConfig();
535                 writer.println(sm.getString("managerServlet.saved"));
536             } catch (Exception JavaDoc e) {
537                 log("managerServlet.storeConfig", e);
538                 writer.println(sm.getString("managerServlet.exception",
539                                             e.toString()));
540                 return;
541             }
542         } else {
543             String JavaDoc contextPath = path;
544             if (path.equals("/")) {
545                 contextPath = "";
546             }
547             Context JavaDoc context = (Context JavaDoc) host.findChild(contextPath);
548             if (context == null) {
549                 writer.println(sm.getString("managerServlet.noContext", path));
550                 return;
551             }
552             try {
553                 ((StandardServer) server).storeContext(context);
554                 writer.println(sm.getString("managerServlet.savedContext",
555                                path));
556             } catch (Exception JavaDoc e) {
557                 log("managerServlet.save[" + path + "]", e);
558                 writer.println(sm.getString("managerServlet.exception",
559                                             e.toString()));
560                 return;
561             }
562         }
563
564     }
565
566
567     /**
568      * Deploy a web application archive (included in the current request)
569      * at the specified context path.
570      *
571      * @param writer Writer to render results to
572      * @param path Context path of the application to be installed
573      * @param tag Tag to be associated with the webapp
574      * @param request Servlet request we are processing
575      */

576     protected synchronized void deploy
577         (PrintWriter JavaDoc writer, String JavaDoc path,
578          String JavaDoc tag, boolean update, HttpServletRequest JavaDoc request) {
579
580         if (debug >= 1) {
581             log("deploy: Deploying web application at '" + path + "'");
582         }
583
584         // Validate the requested context path
585
if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
586             writer.println(sm.getString("managerServlet.invalidPath", path));
587             return;
588         }
589         String JavaDoc displayPath = path;
590         if( path.equals("/") )
591             path = "";
592         String JavaDoc basename = getDocBase(path);
593
594         // Check if app already exists, or undeploy it if updating
595
Context JavaDoc context = (Context JavaDoc) host.findChild(path);
596         if (update) {
597             if (context != null) {
598                 undeploy(writer, displayPath);
599             }
600             context = (Context JavaDoc) host.findChild(path);
601         }
602         if (context != null) {
603             writer.println
604                 (sm.getString("managerServlet.alreadyContext",
605                               displayPath));
606             return;
607         }
608
609         // Calculate the base path
610
File JavaDoc deployedPath = deployed;
611         if (tag != null) {
612             deployedPath = new File JavaDoc(versioned, tag);
613             deployedPath.mkdirs();
614         }
615
616         // Upload the web application archive to a local WAR file
617
File JavaDoc localWar = new File JavaDoc(deployedPath, basename + ".war");
618         if (debug >= 2) {
619             log("Uploading WAR file to " + localWar);
620         }
621
622         // Copy WAR to appBase
623
try {
624             if (!isServiced(path)) {
625                 addServiced(path);
626                 try {
627                     // Upload WAR
628
uploadWar(request, localWar);
629                     // Copy WAR and XML to the host app base if needed
630
if (tag != null) {
631                         deployedPath = deployed;
632                         File JavaDoc localWarCopy = new File JavaDoc(deployedPath, basename + ".war");
633                         copy(localWar, localWarCopy);
634                         localWar = localWarCopy;
635                         copy(localWar, new File JavaDoc(getAppBase(), basename + ".war"));
636                     }
637                     // Perform new deployment
638
check(path);
639                 } finally {
640                     removeServiced(path);
641                 }
642             }
643         } catch (Exception JavaDoc e) {
644             log("managerServlet.check[" + displayPath + "]", e);
645             writer.println(sm.getString("managerServlet.exception",
646                                         e.toString()));
647             return;
648         }
649         
650         context = (Context JavaDoc) host.findChild(path);
651         if (context != null && context.getConfigured()) {
652             writer.println(sm.getString("managerServlet.deployed", displayPath));
653         } else {
654             // Something failed
655
writer.println(sm.getString("managerServlet.deployFailed", displayPath));
656         }
657         
658     }
659
660
661     /**
662      * Install an application for the specified path from the specified
663      * web application archive.
664      *
665      * @param writer Writer to render results to
666      * @param tag Revision tag to deploy from
667      * @param path Context path of the application to be installed
668      */

669     protected void deploy(PrintWriter JavaDoc writer, String JavaDoc path, String JavaDoc tag) {
670
671         // Validate the requested context path
672
if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
673             writer.println(sm.getString("managerServlet.invalidPath", path));
674             return;
675         }
676         String JavaDoc displayPath = path;
677         if( path.equals("/") )
678             path = "";
679
680         // Calculate the base path
681
File JavaDoc deployedPath = versioned;
682         if (tag != null) {
683             deployedPath = new File JavaDoc(deployedPath, tag);
684         }
685
686         // Find the local WAR file
687
File JavaDoc localWar = new File JavaDoc(deployedPath, getDocBase(path) + ".war");
688         // Find the local context deployment file (if any)
689
File JavaDoc localXml = new File JavaDoc(configBase, getConfigFile(path) + ".xml");
690
691         // Check if app already exists, or undeploy it if updating
692
Context JavaDoc context = (Context JavaDoc) host.findChild(path);
693         if (context != null) {
694             undeploy(writer, displayPath);
695         }
696
697         // Copy WAR to appBase
698
try {
699             if (!isServiced(path)) {
700                 addServiced(path);
701                 try {
702                     copy(localWar, new File JavaDoc(getAppBase(), getDocBase(path) + ".war"));
703                     // Perform new deployment
704
check(path);
705                 } finally {
706                     removeServiced(path);
707                 }
708             }
709         } catch (Exception JavaDoc e) {
710             log("managerServlet.check[" + displayPath + "]", e);
711             writer.println(sm.getString("managerServlet.exception",
712                                         e.toString()));
713             return;
714         }
715         
716         context = (Context JavaDoc) host.findChild(path);
717         if (context != null && context.getConfigured()) {
718             writer.println(sm.getString("managerServlet.deployed", displayPath));
719         } else {
720             // Something failed
721
writer.println(sm.getString("managerServlet.deployFailed", displayPath));
722         }
723         
724     }
725
726
727     /**
728      * Install an application for the specified path from the specified
729      * web application archive.
730      *
731      * @param writer Writer to render results to
732      * @param config URL of the context configuration file to be installed
733      * @param path Context path of the application to be installed
734      * @param war URL of the web application archive to be installed
735      * @param update true to override any existing webapp on the path
736      */

737     protected void deploy(PrintWriter JavaDoc writer, String JavaDoc config,
738             String JavaDoc path, String JavaDoc war, boolean update) {
739         
740         if (config != null && config.length() == 0) {
741             config = null;
742         }
743         if (war != null && war.length() == 0) {
744             war = null;
745         }
746         
747         if (debug >= 1) {
748             if (config != null && config.length() > 0) {
749                 if (war != null) {
750                     log("install: Installing context configuration at '" +
751                             config + "' from '" + war + "'");
752                 } else {
753                     log("install: Installing context configuration at '" +
754                             config + "'");
755                 }
756             } else {
757                 if (path != null && path.length() > 0) {
758                     log("install: Installing web application at '" + path +
759                             "' from '" + war + "'");
760                 } else {
761                     log("install: Installing web application from '" + war + "'");
762                 }
763             }
764         }
765         
766         if (path == null || path.length() == 0 || !path.startsWith("/")) {
767             writer.println(sm.getString("managerServlet.invalidPath",
768                                         RequestUtil.filter(path)));
769             return;
770         }
771         String JavaDoc displayPath = path;
772         if("/".equals(path)) {
773             path = "";
774         }
775         
776         // Check if app already exists, or undeploy it if updating
777
Context JavaDoc context = (Context JavaDoc) host.findChild(path);
778         if (update) {
779             if (context != null) {
780                 undeploy(writer, displayPath);
781             }
782             context = (Context JavaDoc) host.findChild(path);
783         }
784         if (context != null) {
785             writer.println
786             (sm.getString("managerServlet.alreadyContext",
787                     displayPath));
788             return;
789         }
790         
791         if (config != null && (config.startsWith("file:"))) {
792             config = config.substring("file:".length());
793         }
794         if (war != null && (war.startsWith("file:"))) {
795             war = war.substring("file:".length());
796         }
797         
798         try {
799             if (!isServiced(path)) {
800                 addServiced(path);
801                 try {
802                     if (config != null) {
803                         copy(new File JavaDoc(config),
804                                 <