FileDocCategorySizeDatePackage
ManagerServlet.javaAPI DocApache Tomcat 6.0.1460735Fri Jul 20 04:20:32 BST 2007org.apache.catalina.manager

ManagerServlet

public class ManagerServlet extends HttpServlet implements org.apache.catalina.ContainerServlet
Servlet that enables remote management of the web applications installed within the same virtual host as this web application is. Normally, this functionality will be protected by a security constraint in the web application deployment descriptor. However, this requirement can be relaxed during testing.

This servlet examines the value returned by getPathInfo() and related query parameters to determine what action is being requested. The following actions and parameters (starting after the servlet path) are supported:

  • /deploy?config={config-url} - Install and start a new web application, based on the contents of the context configuration file found at the specified URL. The docBase attribute of the context configuration file is used to locate the actual WAR or directory containing the application.
  • /deploy?config={config-url}&war={war-url}/ - Install and start a new web application, based on the contents of the context configuration file found at {config-url}, overriding the docBase attribute with the contents of the web application archive found at {war-url}.
  • /deploy?path=/xxx&war={war-url} - Install and start a new web application attached to context path /xxx, based on the contents of the web application archive found at the specified URL.
  • /list - List the context paths of all currently installed web applications for this virtual host. Each context will be listed with the following format path:status:sessions. Where path is the context path. Status is either running or stopped. Sessions is the number of active Sessions.
  • /reload?path=/xxx - Reload the Java classes and resources for the application at the specified path.
  • /resources?type=xxxx - Enumerate the available global JNDI resources, optionally limited to those of the specified type (fully qualified Java class name), if available.
  • /roles - Enumerate the available security role names and descriptions from the user database connected to the users resource reference.
  • /serverinfo - Display system OS and JVM properties.
  • /expire?path=/xxx - List session idle timeinformation about the web application attached to context path /xxx for this virtual host.
  • /expire?path=/xxx&idle=mm - Expire sessions for the context path /xxx which were idle for at least mm minutes.
  • /start?path=/xxx - Start the web application attached to context path /xxx for this virtual host.
  • /stop?path=/xxx - Stop the web application attached to context path /xxx for this virtual host.
  • /undeploy?path=/xxx - Shutdown and remove the web application attached to context path /xxx for this virtual host, and remove the underlying WAR file or document base directory. (NOTE - This is only allowed if the WAR file or document base is stored in the appBase directory of this host, typically as a result of being placed there via the /deploy command.

Use path=/ for the ROOT context.

The syntax of the URL for a web application archive must conform to one of the following patterns to be successfully deployed:

  • file:/absolute/path/to/a/directory - You can specify the absolute path of a directory that contains the unpacked version of a web application. This directory will be attached to the context path you specify without any changes.
  • jar:file:/absolute/path/to/a/warfile.war!/ - You can specify a URL to a local web application archive file. The syntax must conform to the rules specified by the JarURLConnection class for a reference to an entire JAR file.
  • jar:http://hostname:port/path/to/a/warfile.war!/ - You can specify a URL to a remote (HTTP-accessible) web application archive file. The syntax must conform to the rules specified by the JarURLConnection class for a reference to an entire JAR file.

NOTE - Attempting to reload or remove the application containing this servlet itself will not succeed. Therefore, this servlet should generally be deployed as a separate web application within the virtual host to be managed.

NOTE - For security reasons, this application will not operate when accessed via the invoker servlet. You must explicitly map this servlet with a servlet mapping, and you will always want to protect it with appropriate security constraints as well.

The following servlet initialization parameters are recognized:

  • debug - The debugging detail level that controls the amount of information that is logged by this servlet. Default is zero.
author
Craig R. McClanahan
author
Remy Maucherat
version
$Revision: 532461 $ $Date: 2007-04-25 21:56:25 +0200 (mer., 25 avr. 2007) $

Fields Summary
protected File
configBase
Path where context descriptors should be deployed.
protected org.apache.catalina.Context
context
The Context container associated with our web application.
protected int
debug
The debugging detail level for this servlet.
protected File
deployed
File object representing the directory into which the deploy() command will store the WAR and context configuration files that have been uploaded.
protected File
versioned
Path used to store revisions of webapps.
protected File
contextDescriptors
Path used to store context descriptors.
protected org.apache.catalina.Host
host
The associated host.
protected File
appBase
The host appBase.
protected MBeanServer
mBeanServer
MBean server.
protected ObjectName
oname
The associated deployer ObjectName.
protected Context
global
The global JNDI NamingContext for this server, if available.
protected static org.apache.catalina.util.StringManager
sm
The string manager for this package.
protected org.apache.catalina.Wrapper
wrapper
The Wrapper container associated with this servlet.
Constructors Summary
Methods Summary
protected voidaddServiced(java.lang.String name)
Invoke the addServiced method on the deployer.

        String[] params = { name };
        String[] signature = { "java.lang.String" };
        mBeanServer.invoke(oname, "addServiced", params, signature);
    
protected voidcheck(java.lang.String name)
Invoke the check method on the deployer.

        String[] params = { name };
        String[] signature = { "java.lang.String" };
        mBeanServer.invoke(oname, "check", params, signature);
    
public static booleancopy(java.io.File src, java.io.File dest)
Copy the specified file or directory to the destination.

param
src File object representing the source
param
dest File object representing the destination

        boolean result = false;
        try {
            if( src != null &&
                    !src.getCanonicalPath().equals(dest.getCanonicalPath()) ) {
                result = copyInternal(src, dest, new byte[4096]);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    
public static booleancopyInternal(java.io.File src, java.io.File dest, byte[] buf)
Copy the specified file or directory to the destination.

param
src File object representing the source
param
dest File object representing the destination

        
        boolean result = true;
        
        String files[] = null;
        if (src.isDirectory()) {
            files = src.list();
            result = dest.mkdir();
        } else {
            files = new String[1];
            files[0] = "";
        }
        if (files == null) {
            files = new String[0];
        }
        for (int i = 0; (i < files.length) && result; i++) {
            File fileSrc = new File(src, files[i]);
            File fileDest = new File(dest, files[i]);
            if (fileSrc.isDirectory()) {
                result = copyInternal(fileSrc, fileDest, buf);
            } else {
                FileInputStream is = null;
                FileOutputStream os = null;
                try {
                    is = new FileInputStream(fileSrc);
                    os = new FileOutputStream(fileDest);
                    int len = 0;
                    while (true) {
                        len = is.read(buf);
                        if (len == -1)
                            break;
                        os.write(buf, 0, len);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    result = false;
                } finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                        }
                    }
                    if (os != null) {
                        try {
                            os.close();
                        } catch (IOException e) {
                        }
                    }
                }
            }
        }
        return result;
        
    
protected voiddeploy(java.io.PrintWriter writer, java.lang.String config, java.lang.String path, java.lang.String war, boolean update)
Install an application for the specified path from the specified web application archive.

param
writer Writer to render results to
param
config URL of the context configuration file to be installed
param
path Context path of the application to be installed
param
war URL of the web application archive to be installed
param
update true to override any existing webapp on the path

        
        if (config != null && config.length() == 0) {
            config = null;
        }
        if (war != null && war.length() == 0) {
            war = null;
        }
        
        if (debug >= 1) {
            if (config != null && config.length() > 0) {
                if (war != null) {
                    log("install: Installing context configuration at '" +
                            config + "' from '" + war + "'");
                } else {
                    log("install: Installing context configuration at '" +
                            config + "'");
                }
            } else {
                if (path != null && path.length() > 0) {
                    log("install: Installing web application at '" + path +
                            "' from '" + war + "'");
                } else {
                    log("install: Installing web application from '" + war + "'");
                }
            }
        }
        
        if (path == null || path.length() == 0 || !path.startsWith("/")) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if("/".equals(path)) {
            path = "";
        }
        
        // Check if app already exists, or undeploy it if updating
        Context context = (Context) host.findChild(path);
        if (update) {
            if (context != null) {
                undeploy(writer, displayPath);
            }
            context = (Context) host.findChild(path);
        }
        if (context != null) {
            writer.println
            (sm.getString("managerServlet.alreadyContext",
                    displayPath));
            return;
        }
        
        if (config != null && (config.startsWith("file:"))) {
            config = config.substring("file:".length());
        }
        if (war != null && (war.startsWith("file:"))) {
            war = war.substring("file:".length());
        }
        
        try {
            if (!isServiced(path)) {
                addServiced(path);
                try {
                    if (config != null) {
                        configBase.mkdirs();
                        copy(new File(config), 
                                new File(configBase, getConfigFile(path) + ".xml"));
                    }
                    if (war != null) {
                        if (war.endsWith(".war")) {
                            copy(new File(war), 
                                    new File(getAppBase(), getDocBase(path) + ".war"));
                        } else {
                            copy(new File(war), 
                                    new File(getAppBase(), getDocBase(path)));
                        }
                    }
                    // Perform new deployment
                    check(path);
                } finally {
                    removeServiced(path);
                }
            }
            context = (Context) host.findChild(path);
            if (context != null && context.getConfigured()) {
                writer.println(sm.getString("managerServlet.deployed", displayPath));
            } else {
                // Something failed
                writer.println(sm.getString("managerServlet.deployFailed", displayPath));
            }
        } catch (Throwable t) {
            log("ManagerServlet.install[" + displayPath + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                    t.toString()));
        }
        
    
protected synchronized voiddeploy(java.io.PrintWriter writer, java.lang.String path, java.lang.String tag, boolean update, javax.servlet.http.HttpServletRequest request)
Deploy a web application archive (included in the current request) at the specified context path.

param
writer Writer to render results to
param
path Context path of the application to be installed
param
tag Tag to be associated with the webapp
param
request Servlet request we are processing


        if (debug >= 1) {
            log("deploy: Deploying web application at '" + path + "'");
        }

        // Validate the requested context path
        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
            writer.println(sm.getString("managerServlet.invalidPath", path));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";
        String basename = getDocBase(path);

        // Check if app already exists, or undeploy it if updating
        Context context = (Context) host.findChild(path);
        if (update) {
            if (context != null) {
                undeploy(writer, displayPath);
            }
            context = (Context) host.findChild(path);
        }
        if (context != null) {
            writer.println
                (sm.getString("managerServlet.alreadyContext",
                              displayPath));
            return;
        }

        // Calculate the base path
        File deployedPath = deployed;
        if (tag != null) {
            deployedPath = new File(versioned, tag);
            deployedPath.mkdirs();
        }

        // Upload the web application archive to a local WAR file
        File localWar = new File(deployedPath, basename + ".war");
        if (debug >= 2) {
            log("Uploading WAR file to " + localWar);
        }

        // Copy WAR to appBase
        try {
            if (!isServiced(path)) {
                addServiced(path);
                try {
                    // Upload WAR
                    uploadWar(request, localWar);
                    // Copy WAR and XML to the host app base if needed
                    if (tag != null) {
                        deployedPath = deployed;
                        File localWarCopy = new File(deployedPath, basename + ".war");
                        copy(localWar, localWarCopy);
                        localWar = localWarCopy;
                        copy(localWar, new File(getAppBase(), basename + ".war"));
                    }
                    // Perform new deployment
                    check(path);
                } finally {
                    removeServiced(path);
                }
            }
        } catch (Exception e) {
            log("managerServlet.check[" + displayPath + "]", e);
            writer.println(sm.getString("managerServlet.exception",
                                        e.toString()));
            return;
        }
        
        context = (Context) host.findChild(path);
        if (context != null && context.getConfigured()) {
            writer.println(sm.getString("managerServlet.deployed", displayPath));
        } else {
            // Something failed
            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
        }
        
    
protected voiddeploy(java.io.PrintWriter writer, java.lang.String path, java.lang.String tag)
Install an application for the specified path from the specified web application archive.

param
writer Writer to render results to
param
tag Revision tag to deploy from
param
path Context path of the application to be installed


        // Validate the requested context path
        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
            writer.println(sm.getString("managerServlet.invalidPath", path));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";

        // Calculate the base path
        File deployedPath = versioned;
        if (tag != null) {
            deployedPath = new File(deployedPath, tag);
        }

        // Find the local WAR file
        File localWar = new File(deployedPath, getDocBase(path) + ".war");
        // Find the local context deployment file (if any)
        File localXml = new File(configBase, getConfigFile(path) + ".xml");

        // Check if app already exists, or undeploy it if updating
        Context context = (Context) host.findChild(path);
        if (context != null) {
            undeploy(writer, displayPath);
        }

        // Copy WAR to appBase
        try {
            if (!isServiced(path)) {
                addServiced(path);
                try {
                    copy(localWar, new File(getAppBase(), getDocBase(path) + ".war"));
                    // Perform new deployment
                    check(path);
                } finally {
                    removeServiced(path);
                }
            }
        } catch (Exception e) {
            log("managerServlet.check[" + displayPath + "]", e);
            writer.println(sm.getString("managerServlet.exception",
                                        e.toString()));
            return;
        }
        
        context = (Context) host.findChild(path);
        if (context != null && context.getConfigured()) {
            writer.println(sm.getString("managerServlet.deployed", displayPath));
        } else {
            // Something failed
            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
        }
        
    
public voiddestroy()
Finalize this servlet.


        ;       // No actions necessary

    
public voiddoGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
Process a GET request for the specified resource.

param
request The servlet request we are processing
param
response The servlet response we are creating
exception
IOException if an input/output error occurs
exception
ServletException if a servlet-specified error occurs


        // Verify that we were not accessed using the invoker servlet
        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
            throw new UnavailableException
                (sm.getString("managerServlet.cannotInvoke"));

        // Identify the request parameters that we need
        String command = request.getPathInfo();
        if (command == null)
            command = request.getServletPath();
        String config = request.getParameter("config");
        String path = request.getParameter("path");
        String type = request.getParameter("type");
        String war = request.getParameter("war");
        String tag = request.getParameter("tag");
        boolean update = false;
        if ((request.getParameter("update") != null) 
            && (request.getParameter("update").equals("true"))) {
            update = true;
        }

        // Prepare our output writer to generate the response message
        response.setContentType("text/plain; charset=" + Constants.CHARSET);
        PrintWriter writer = response.getWriter();

        // Process the requested command (note - "/deploy" is not listed here)
        if (command == null) {
            writer.println(sm.getString("managerServlet.noCommand"));
        } else if (command.equals("/deploy")) {
            if (war != null || config != null) {
                deploy(writer, config, path, war, update);
            } else {
                deploy(writer, path, tag);
            }
        } else if (command.equals("/install")) {
            // Deprecated
            deploy(writer, config, path, war, false);
        } else if (command.equals("/list")) {
            list(writer);
        } else if (command.equals("/reload")) {
            reload(writer, path);
        } else if (command.equals("/remove")) {
            // Deprecated
            undeploy(writer, path);
        } else if (command.equals("/resources")) {
            resources(writer, type);
        } else if (command.equals("/roles")) {
            roles(writer);
        } else if (command.equals("/save")) {
            save(writer, path);
        } else if (command.equals("/serverinfo")) {
            serverinfo(writer);
        } else if (command.equals("/expire")) {
            expireSessions(writer, path, request);
        } else if (command.equals("/start")) {
            start(writer, path);
        } else if (command.equals("/stop")) {
            stop(writer, path);
        } else if (command.equals("/undeploy")) {
            undeploy(writer, path);
        } else {
            writer.println(sm.getString("managerServlet.unknownCommand",
                                        command));
        }

        // Finish up the response
        writer.flush();
        writer.close();

    
public voiddoPut(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
Process a PUT request for the specified resource.

param
request The servlet request we are processing
param
response The servlet response we are creating
exception
IOException if an input/output error occurs
exception
ServletException if a servlet-specified error occurs


        // Verify that we were not accessed using the invoker servlet
        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
            throw new UnavailableException
                (sm.getString("managerServlet.cannotInvoke"));

        // Identify the request parameters that we need
        String command = request.getPathInfo();
        if (command == null)
            command = request.getServletPath();
        String path = request.getParameter("path");
        String tag = request.getParameter("tag");
        boolean update = false;
        if ((request.getParameter("update") != null) 
            && (request.getParameter("update").equals("true"))) {
            update = true;
        }

        // Prepare our output writer to generate the response message
        response.setContentType("text/plain;charset="+Constants.CHARSET);
        PrintWriter writer = response.getWriter();

        // Process the requested command
        if (command == null) {
            writer.println(sm.getString("managerServlet.noCommand"));
        } else if (command.equals("/deploy")) {
            deploy(writer, path, tag, update, request);
        } else {
            writer.println(sm.getString("managerServlet.unknownCommand",
                                        command));
        }

        // Finish up the response
        writer.flush();
        writer.close();

    
protected voidexpireSessions(java.io.PrintWriter writer, java.lang.String path, javax.servlet.http.HttpServletRequest req)
Extract the expiration request parameter

param
path
param
req

        int idle = -1;
        String idleParam = req.getParameter("idle");
        if (idleParam != null) {
            try {
                idle = Integer.parseInt(idleParam);
            } catch (NumberFormatException e) {
                log("Could not parse idle parameter to an int: " + idleParam);
            }
        }
        sessions(writer, path, idle);
    
protected java.io.FilegetAppBase()
Return a File object representing the "application root" directory for our associated Host.


        if (appBase != null) {
            return appBase;
        }

        File file = new File(host.getAppBase());
        if (!file.isAbsolute())
            file = new File(System.getProperty("catalina.base"),
                            host.getAppBase());
        try {
            appBase = file.getCanonicalFile();
        } catch (IOException e) {
            appBase = file;
        }
        return (appBase);

    
protected java.lang.StringgetConfigFile(java.lang.String path)
Given a context path, get the config file name.

        String basename = null;
        if (path.equals("")) {
            basename = "ROOT";
        } else {
            basename = path.substring(1).replace('/", '#");
        }
        return (basename);
    
protected java.lang.StringgetDocBase(java.lang.String path)
Given a context path, get the config file name.

        String basename = null;
        if (path.equals("")) {
            basename = "ROOT";
        } else {
            basename = path.substring(1);
        }
        return (basename);
    
public org.apache.catalina.WrappergetWrapper()
Return the Wrapper with which we are associated.



    // ----------------------------------------------- ContainerServlet Methods


                 
       

        return (this.wrapper);

    
public voidinit()
Initialize this servlet.


        // Ensure that our ContainerServlet properties have been set
        if ((wrapper == null) || (context == null))
            throw new UnavailableException
                (sm.getString("managerServlet.noWrapper"));

        // Verify that we were not accessed using the invoker servlet
        String servletName = getServletConfig().getServletName();
        if (servletName == null)
            servletName = "";
        if (servletName.startsWith("org.apache.catalina.INVOKER."))
            throw new UnavailableException
                (sm.getString("managerServlet.cannotInvoke"));

        // Set our properties from the initialization parameters
        String value = null;
        try {
            value = getServletConfig().getInitParameter("debug");
            debug = Integer.parseInt(value);
        } catch (Throwable t) {
            ;
        }

        // Acquire global JNDI resources if available
        Server server = ServerFactory.getServer();
        if ((server != null) && (server instanceof StandardServer)) {
            global = ((StandardServer) server).getGlobalNamingContext();
        }

        // Calculate the directory into which we will be deploying applications
        versioned = (File) getServletContext().getAttribute
            ("javax.servlet.context.tempdir");

        // Identify the appBase of the owning Host of this Context
        // (if any)
        String appBase = ((Host) context.getParent()).getAppBase();
        deployed = new File(appBase);
        if (!deployed.isAbsolute()) {
            deployed = new File(System.getProperty("catalina.base"),
                                appBase);
        }
        configBase = new File(System.getProperty("catalina.base"), "conf");
        Container container = context;
        Container host = null;
        Container engine = null;
        while (container != null) {
            if (container instanceof Host)
                host = container;
            if (container instanceof Engine)
                engine = container;
            container = container.getParent();
        }
        if (engine != null) {
            configBase = new File(configBase, engine.getName());
        }
        if (host != null) {
            configBase = new File(configBase, host.getName());
        }
        // Note: The directory must exist for this to work.

        // Log debugging messages as necessary
        if (debug >= 1) {
            log("init: Associated with Deployer '" +
                oname + "'");
            if (global != null) {
                log("init: Global resources are available");
            }
        }

    
protected booleanisDeployed(java.lang.String name)
Invoke the isDeployed method on the deployer.

        String[] params = { name };
        String[] signature = { "java.lang.String" };
        Boolean result = 
            (Boolean) mBeanServer.invoke(oname, "isDeployed", params, signature);
        return result.booleanValue();
    
protected booleanisServiced(java.lang.String name)
Invoke the isServiced method on the deployer.

        String[] params = { name };
        String[] signature = { "java.lang.String" };
        Boolean result = 
            (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature);
        return result.booleanValue();
    
protected voidlist(java.io.PrintWriter writer)
Render a list of the currently active Contexts in our virtual host.

param
writer Writer to render to


        if (debug >= 1)
            log("list: Listing contexts for virtual host '" +
                host.getName() + "'");

        writer.println(sm.getString("managerServlet.listed",
                                    host.getName()));
        Container[] contexts = host.findChildren();
        for (int i = 0; i < contexts.length; i++) {
            Context context = (Context) contexts[i];
            String displayPath = context.getPath();
            if( displayPath.equals("") )
                displayPath = "/";
            if (context != null ) {
                if (context.getAvailable()) {
                    writer.println(sm.getString("managerServlet.listitem",
                                                displayPath,
                                                "running",
                                      "" + context.getManager().findSessions().length,
                                                context.getDocBase()));
                } else {
                    writer.println(sm.getString("managerServlet.listitem",
                                                displayPath,
                                                "stopped",
                                                "0",
                                                context.getDocBase()));
                }
            }
        }
    
protected voidprintResources(java.io.PrintWriter writer, java.lang.String prefix, javax.naming.Context namingContext, java.lang.String type, java.lang.Class clazz)
List the resources of the given context.


        try {
            NamingEnumeration items = namingContext.listBindings("");
            while (items.hasMore()) {
                Binding item = (Binding) items.next();
                if (item.getObject() instanceof javax.naming.Context) {
                    printResources
                        (writer, prefix + item.getName() + "/",
                         (javax.naming.Context) item.getObject(), type, clazz);
                } else {
                    if ((clazz != null) &&
                        (!(clazz.isInstance(item.getObject())))) {
                        continue;
                    }
                    writer.print(prefix + item.getName());
                    writer.print(':");
                    writer.print(item.getClassName());
                    // Do we want a description if available?
                    writer.println();
                }
            }
        } catch (Throwable t) {
            log("ManagerServlet.resources[" + type + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidreload(java.io.PrintWriter writer, java.lang.String path)
Reload the web application at the specified context path.

param
writer Writer to render to
param
path Context path of the application to be restarted


        if (debug >= 1)
            log("restart: Reloading web application at '" + path + "'");

        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";

        try {
            Context context = (Context) host.findChild(path);
            if (context == null) {
                writer.println(sm.getString
                               ("managerServlet.noContext",
                                   RequestUtil.filter(displayPath)));
                return;
            }
            // It isn't possible for the manager to reload itself
            if (context.getPath().equals(this.context.getPath())) {
                writer.println(sm.getString("managerServlet.noSelf"));
                return;
            }
            context.reload();
            writer.println
                (sm.getString("managerServlet.reloaded", displayPath));
        } catch (Throwable t) {
            log("ManagerServlet.reload[" + displayPath + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidremoveServiced(java.lang.String name)
Invoke the removeServiced method on the deployer.

        String[] params = { name };
        String[] signature = { "java.lang.String" };
        mBeanServer.invoke(oname, "removeServiced", params, signature);
    
protected voidresources(java.io.PrintWriter writer, java.lang.String type)
Render a list of available global JNDI resources.

param
type Fully qualified class name of the resource type of interest, or null to list resources of all types


        if (debug >= 1) {
            if (type != null) {
                log("resources:  Listing resources of type " + type);
            } else {
                log("resources:  Listing resources of all types");
            }
        }

        // Is the global JNDI resources context available?
        if (global == null) {
            writer.println(sm.getString("managerServlet.noGlobal"));
            return;
        }

        // Enumerate the global JNDI resources of the requested type
        if (type != null) {
            writer.println(sm.getString("managerServlet.resourcesType",
                                        type));
        } else {
            writer.println(sm.getString("managerServlet.resourcesAll"));
        }

        Class clazz = null;
        try {
            if (type != null) {
                clazz = Class.forName(type);
            }
        } catch (Throwable t) {
            log("ManagerServlet.resources[" + type + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
            return;
        }

        printResources(writer, "", global, type, clazz);

    
protected voidroles(java.io.PrintWriter writer)
Render a list of security role names (and corresponding descriptions) from the org.apache.catalina.UserDatabase resource that is connected to the users resource reference. Typically, this will be the global user database, but can be adjusted if you have different user databases for different virtual hosts.

param
writer Writer to render to


        if (debug >= 1) {
            log("roles:  List security roles from user database");
        }

        // Look up the UserDatabase instance we should use
        UserDatabase database = null;
        try {
            InitialContext ic = new InitialContext();
            database = (UserDatabase) ic.lookup("java:comp/env/users");
        } catch (NamingException e) {
            writer.println(sm.getString("managerServlet.userDatabaseError"));
            log("java:comp/env/users", e);
            return;
        }
        if (database == null) {
            writer.println(sm.getString("managerServlet.userDatabaseMissing"));
            return;
        }

        // Enumerate the available roles
        writer.println(sm.getString("managerServlet.rolesList"));
        Iterator roles = database.getRoles();
        if (roles != null) {
            while (roles.hasNext()) {
                Role role = (Role) roles.next();
                writer.print(role.getRolename());
                writer.print(':");
                if (role.getDescription() != null) {
                    writer.print(role.getDescription());
                }
                writer.println();
            }
        }


    
protected synchronized voidsave(java.io.PrintWriter writer, java.lang.String path)
Store server configuration.

param
path Optional context path to save


        Server server = ServerFactory.getServer();

        if (!(server instanceof StandardServer)) {
            writer.println(sm.getString("managerServlet.saveFail", server));
            return;
        }

        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
            try {
                ((StandardServer) server).storeConfig();
                writer.println(sm.getString("managerServlet.saved"));
            } catch (Exception e) {
                log("managerServlet.storeConfig", e);
                writer.println(sm.getString("managerServlet.exception",
                                            e.toString()));
                return;
            }
        } else {
            String contextPath = path;
            if (path.equals("/")) {
                contextPath = "";
            }
            Context context = (Context) host.findChild(contextPath);
            if (context == null) {
                writer.println(sm.getString("managerServlet.noContext", path));
                return;
            }
            try {
                ((StandardServer) server).storeContext(context);
                writer.println(sm.getString("managerServlet.savedContext", 
                               path));
            } catch (Exception e) {
                log("managerServlet.save[" + path + "]", e);
                writer.println(sm.getString("managerServlet.exception",
                                            e.toString()));
                return;
            }
        }

    
protected voidserverinfo(java.io.PrintWriter writer)
Writes System OS and JVM properties.

param
writer Writer to render to

        if (debug >= 1)
            log("serverinfo");
        try {
            StringBuffer props = new StringBuffer();
            props.append("OK - Server info");
            props.append("\nTomcat Version: ");
            props.append(ServerInfo.getServerInfo());
            props.append("\nOS Name: ");
            props.append(System.getProperty("os.name"));
            props.append("\nOS Version: ");
            props.append(System.getProperty("os.version"));
            props.append("\nOS Architecture: ");
            props.append(System.getProperty("os.arch"));
            props.append("\nJVM Version: ");
            props.append(System.getProperty("java.runtime.version"));
            props.append("\nJVM Vendor: ");
            props.append(System.getProperty("java.vm.vendor"));
            writer.println(props.toString());
        } catch (Throwable t) {
            getServletContext().log("ManagerServlet.serverinfo",t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }
    
protected voidsessions(java.io.PrintWriter writer, java.lang.String path, int idle)
Session information for the web application at the specified context path. Displays a profile of session lastAccessedTime listing number of sessions for each 10 minute interval up to 10 hours.

param
writer Writer to render to
param
path Context path of the application to list session information for
param
idle Expire all sessions with idle time ≥ idle for this context


        if (debug >= 1) {
            log("sessions: Session information for web application at '" + path + "'");
            if (idle >= 0)
                log("sessions: Session expiration for " + idle + " minutes '" + path + "'");
        }

        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";
        try {
            Context context = (Context) host.findChild(path);
            if (context == null) {
                writer.println(sm.getString("managerServlet.noContext",
                                            RequestUtil.filter(displayPath)));
                return;
            }
            int maxCount = 60;
            int maxInactiveInterval = context.getManager().getMaxInactiveInterval()/60;
            int histoInterval = maxInactiveInterval / maxCount;
            if ( histoInterval * maxCount < maxInactiveInterval ) 
                histoInterval++;
            maxCount = maxInactiveInterval / histoInterval;
            if ( histoInterval * maxCount < maxInactiveInterval ) 
                maxCount++;

            writer.println(sm.getString("managerServlet.sessions", displayPath));
            writer.println(sm.getString("managerServlet.sessiondefaultmax",
                                "" + maxInactiveInterval));
            Session [] sessions = context.getManager().findSessions();
            int [] timeout = new int[maxCount];
            int notimeout = 0;
            int expired = 0;
            long now = System.currentTimeMillis();
            for (int i = 0; i < sessions.length; i++) {
                int time = (int)((now-sessions[i].getLastAccessedTime())/1000);
                if (idle >= 0 && time >= idle*60) {
                    sessions[i].expire();
                    idle++;
                }
                time=time/60/histoInterval;
                if (time < 0)
                    notimeout++;
                else if (time >= maxCount)
                    timeout[maxCount-1]++;
                else
                    timeout[time]++;
            }
            if (timeout[0] > 0)
                writer.println(sm.getString("managerServlet.sessiontimeout",
                                            "<" + histoInterval, "" + timeout[0]));
            for (int i = 1; i < maxCount-1; i++) {
                if (timeout[i] > 0)
                    writer.println(sm.getString("managerServlet.sessiontimeout",
                                     "" + (i)*histoInterval + " - <" + (i+1)*histoInterval,
                                                "" + timeout[i]));
            }
            if (timeout[maxCount-1] > 0)
                writer.println(sm.getString("managerServlet.sessiontimeout",
                                            ">=" + maxCount*histoInterval,
                                            "" + timeout[maxCount-1]));
            if (notimeout > 0)
                writer.println(sm.getString("managerServlet.sessiontimeout",
                                            "unlimited","" + notimeout));
            if (idle >= 0)
                writer.println(sm.getString("managerServlet.sessiontimeout",
                                            "" + idle,"expired " + expired));
        } catch (Throwable t) {
            log("ManagerServlet.sessions[" + displayPath + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidsessions(java.io.PrintWriter writer, java.lang.String path)
Session information for the web application at the specified context path. Displays a profile of session lastAccessedTime listing number of sessions for each 10 minute interval up to 10 hours.

param
writer Writer to render to
param
path Context path of the application to list session information for

        sessions(writer, path, -1);
    
public voidsetWrapper(org.apache.catalina.Wrapper wrapper)
Set the Wrapper with which we are associated.

param
wrapper The new wrapper


        this.wrapper = wrapper;
        if (wrapper == null) {
            context = null;
            host = null;
            oname = null;
        } else {
            context = (Context) wrapper.getParent();
            host = (Host) context.getParent();
            Engine engine = (Engine) host.getParent();
            try {
                oname = new ObjectName(engine.getName() 
                        + ":type=Deployer,host=" + host.getName());
            } catch (Exception e) {
                // ?
            }
        }

        // Retrieve the MBean server
        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
        
    
protected voidstart(java.io.PrintWriter writer, java.lang.String path)
Start the web application at the specified context path.

param
writer Writer to render to
param
path Context path of the application to be started


        if (debug >= 1)
            log("start: Starting web application at '" + path + "'");

        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";

        try {
            Context context = (Context) host.findChild(path);
            if (context == null) {
                writer.println(sm.getString("managerServlet.noContext", 
                                            RequestUtil.filter(displayPath)));
                return;
            }
            ((Lifecycle) context).start();
            if (context.getAvailable())
                writer.println
                    (sm.getString("managerServlet.started", displayPath));
            else
                writer.println
                    (sm.getString("managerServlet.startFailed", displayPath));
        } catch (Throwable t) {
            getServletContext().log
                (sm.getString("managerServlet.startFailed", displayPath), t);
            writer.println
                (sm.getString("managerServlet.startFailed", displayPath));
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidstop(java.io.PrintWriter writer, java.lang.String path)
Stop the web application at the specified context path.

param
writer Writer to render to
param
path Context path of the application to be stopped


        if (debug >= 1)
            log("stop: Stopping web application at '" + path + "'");

        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";

        try {
            Context context = (Context) host.findChild(path);
            if (context == null) {
                writer.println(sm.getString("managerServlet.noContext", 
                                            RequestUtil.filter(displayPath)));
                return;
            }
            // It isn't possible for the manager to stop itself
            if (context.getPath().equals(this.context.getPath())) {
                writer.println(sm.getString("managerServlet.noSelf"));
                return;
            }
            ((Lifecycle) context).stop();
            writer.println(sm.getString("managerServlet.stopped", displayPath));
        } catch (Throwable t) {
            log("ManagerServlet.stop[" + displayPath + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidundeploy(java.io.PrintWriter writer, java.lang.String path)
Undeploy the web application at the specified context path.

param
writer Writer to render to
param
path Context path of the application to be removed


        if (debug >= 1)
            log("undeploy: Undeploying web application at '" + path + "'");

        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
            writer.println(sm.getString("managerServlet.invalidPath",
                                        RequestUtil.filter(path)));
            return;
        }
        String displayPath = path;
        if( path.equals("/") )
            path = "";

        try {

            // Validate the Context of the specified application
            Context context = (Context) host.findChild(path);
            if (context == null) {
                writer.println(sm.getString("managerServlet.noContext",
                                            RequestUtil.filter(displayPath)));
                return;
            }

            // Identify the appBase of the owning Host of this Context (if any)
            String appBase = null;
            File appBaseDir = null;
            if (context.getParent() instanceof Host) {
                appBase = ((Host) context.getParent()).getAppBase();
                appBaseDir = new File(appBase);
                if (!appBaseDir.isAbsolute()) {
                    appBaseDir = new File(System.getProperty("catalina.base"),
                                          appBase);
                }
            }

            if (!isDeployed(path)) {
                writer.println(sm.getString("managerServlet.notDeployed",
                        RequestUtil.filter(displayPath)));
                return;
            }

            if (!isServiced(path)) {
                addServiced(path);
                try {
                    // Try to stop the context first to be nicer
                    ((Lifecycle) context).stop();
                } catch (Throwable t) {
                    // Ignore
                }
                try {
                    File war = new File(getAppBase(), getDocBase(path) + ".war");
                    File dir = new File(getAppBase(), getDocBase(path));
                    File xml = new File(configBase, getConfigFile(path) + ".xml");
                    if (war.exists()) {
                        war.delete();
                    } else if (dir.exists()) {
                        undeployDir(dir);
                    } else {
                        xml.delete();
                    }
                    // Perform new deployment
                    check(path);
                } finally {
                    removeServiced(path);
                }
            }
            writer.println(sm.getString("managerServlet.undeployed",
                                        displayPath));
        } catch (Throwable t) {
            log("ManagerServlet.undeploy[" + displayPath + "]", t);
            writer.println(sm.getString("managerServlet.exception",
                                        t.toString()));
        }

    
protected voidundeployDir(java.io.File dir)
Delete the specified directory, including all of its contents and subdirectories recursively.

param
dir File object representing the directory to be deleted


        String files[] = dir.list();
        if (files == null) {
            files = new String[0];
        }
        for (int i = 0; i < files.length; i++) {
            File file = new File(dir, files[i]);
            if (file.isDirectory()) {
                undeployDir(file);
            } else {
                file.delete();
            }
        }
        dir.delete();

    
protected voiduploadWar(javax.servlet.http.HttpServletRequest request, java.io.File war)
Upload the WAR file included in this request, and store it at the specified file location.

param
request The servlet request we are processing
param
war The file into which we should store the uploaded WAR
exception
IOException if an I/O error occurs during processing


        war.delete();
        ServletInputStream istream = null;
        BufferedOutputStream ostream = null;
        try {
            istream = request.getInputStream();
            ostream =
                new BufferedOutputStream(new FileOutputStream(war), 1024);
            byte buffer[] = new byte[1024];
            while (true) {
                int n = istream.read(buffer);
                if (n < 0) {
                    break;
                }
                ostream.write(buffer, 0, n);
            }
            ostream.flush();
            ostream.close();
            ostream = null;
            istream.close();
            istream = null;
        } catch (IOException e) {
            war.delete();
            throw e;
        } finally {
            if (ostream != null) {
                try {
                    ostream.close();
                } catch (Throwable t) {
                    ;
                }
                ostream = null;
            }
            if (istream != null) {
                try {
                    istream.close();
                } catch (Throwable t) {
                    ;
                }
                istream = null;
            }
        }