FileDocCategorySizeDatePackage
HostConfig.javaAPI DocGlassfish v2 API33915Fri May 04 22:32:30 BST 2007org.apache.catalina.startup

HostConfig

public class HostConfig extends Object implements org.apache.catalina.LifecycleListener
Startup event listener for a Host that configures the properties of that Host, and the associated defined contexts.
author
Craig R. McClanahan
author
Remy Maucherat
version
$Revision: 1.5 $ $Date: 2007/05/05 05:32:29 $

Fields Summary
private static com.sun.org.apache.commons.logging.Log
log
private File
appBase
App base.
private File
configBase
Config base.
protected String
configClass
The Java class name of the Context configuration class we should use.
protected String
contextClass
The Java class name of the Context implementation we should use.
protected int
debug
The debugging detail level for this component.
protected ArrayList
deployed
The names of applications that we have auto-deployed (to avoid double deployment attempts).
protected org.apache.catalina.Host
host
The Host we are associated with.
protected static final org.apache.catalina.util.StringManager
sm
The string resources for this package.
private boolean
deployXML
Should we deploy XML Context config files?
private boolean
unpackWARs
Should we unpack WAR files when auto-deploying applications in the appBase directory?
private HashMap
webXmlLastModified
Last modified dates of the web.xml files of the contexts, keyed by context name.
private HashMap
contextXmlLastModified
Last modified dates of the Context xml files of the contexts, keyed by context name.
private HashMap
warLastModified
Last modified dates of the source WAR files, keyed by WAR name.
private boolean
xmlValidation
Attribute value used to turn on/off XML validation
private boolean
xmlNamespaceAware
Attribute value used to turn on/off XML namespace awarenes.
Constructors Summary
Methods Summary
protected java.io.FileappBase()
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 voidcheck()
Deploy webapps.


        if (host.getAutoDeploy()) {
            // Deploy apps if the Host allows auto deploying
            deployApps();
            // Check for web.xml modification
            checkContextLastModified();
        }

    
protected voidcheckContextLastModified()
Check deployment descriptors last modified date.


        if (!(host instanceof Deployer))
            return;

        Deployer deployer = (Deployer) host;

        String[] contextNames = deployer.findDeployedApps();

        for (int i = 0; i < contextNames.length; i++) {

            String contextName = contextNames[i];
            Context context = deployer.findDeployedApp(contextName);

            if (!(context instanceof Lifecycle))
                continue;

            try {
                DirContext resources = context.getResources();
                if (resources == null) {
                    // This can happen if there was an error initializing
                    // the context
                    continue;
                }
                ResourceAttributes webXmlAttributes = 
                    (ResourceAttributes) 
                    resources.getAttributes("/WEB-INF/web.xml");
                ResourceAttributes webInfAttributes = 
                    (ResourceAttributes) 
                    resources.getAttributes("/WEB-INF");
                long newLastModified = webXmlAttributes.getLastModified();
                long webInfLastModified = webInfAttributes.getLastModified();
                Long lastModified = (Long) webXmlLastModified.get(contextName);
                if (lastModified == null) {
                    webXmlLastModified.put
                        (contextName, Long.valueOf(newLastModified));
                } else {
                    if (lastModified.longValue() != newLastModified) {
                        if (newLastModified > (webInfLastModified + 5000)) {
                            webXmlLastModified.remove(contextName);
                            restartContext(context);
                        } else {
                            webXmlLastModified.put
                                (contextName, Long.valueOf(newLastModified));
                        }
                    }
                }
            } catch (NamingException e) {
                ; // Ignore
            }

            Long lastModified = (Long) contextXmlLastModified.get(contextName);
            String configBase = configBase().getPath();
            String configFileName = context.getConfigFile();
            if (configFileName != null) {
                File configFile = new File(configFileName);
                if (!configFile.isAbsolute()) {
                    configFile = new File(System.getProperty("catalina.base"),
                                          configFile.getPath());
                }
                long newLastModified = configFile.lastModified();
                if (lastModified == null) {
                    contextXmlLastModified.put
                        (contextName, Long.valueOf(newLastModified));
                } else {
                    if (lastModified.longValue() != newLastModified) {
                        contextXmlLastModified.remove(contextName);
                        String fileName = configFileName;
                        if (fileName.startsWith(configBase)) {
                            fileName = 
                                fileName.substring(configBase.length() + 1);
                            try {
                                deployed.remove(fileName);
                                if (host.findChild(contextName) != null) {
                                    ((Deployer) host).remove(contextName);
                                }
                            } catch (Throwable t) {
                                log.error(sm.getString
                                          ("hostConfig.undeployJar.error",
                                           fileName), t);
                            }
                            deployApps();
                        }
                    }
                }
            }

        }

        // Check for WAR modification
        if (isUnpackWARs()) {
            File appBase = appBase();
            if (!appBase.exists() || !appBase.isDirectory())
                return;
            String files[] = appBase.list();

            for (int i = 0; i < files.length; i++) {
                if (files[i].endsWith(".war")) {
                    File dir = new File(appBase, files[i]);
                    Long lastModified = (Long) warLastModified.get(files[i]);
                    long dirLastModified = dir.lastModified();
                    if (lastModified == null) {
                        warLastModified.put
                            (files[i], Long.valueOf(dir.lastModified()));
                    } else if (dirLastModified > lastModified.longValue()) {
                        // The WAR has been modified: redeploy
                        String expandedDir = files[i];
                        int period = expandedDir.lastIndexOf(".");
                        if (period >= 0)
                            expandedDir = expandedDir.substring(0, period);
                        File expanded = new File(appBase, expandedDir);
                        String contextPath = "/" + expandedDir;
                        if (contextPath.equals("/ROOT"))
                            contextPath = "";
                        if (dirLastModified > expanded.lastModified()) {
                            try {
                                // Undeploy current application
                                deployed.remove(files[i]);
                                deployed.remove(expandedDir + ".xml");
                                if (host.findChild(contextPath) != null) {
                                    ((Deployer) host).remove(contextPath, 
                                                             false);
                                    ExpandWar.deleteDir(expanded);
                                }
                            } catch (Throwable t) {
                                log.error(sm.getString
                                          ("hostConfig.undeployJar.error",
                                           files[i]), t);
                            }
                            deployApps();
                        }
                        // If deployment was successful, reset 
                        // the last modified values
                        if (host.findChild(contextPath) != null) {
                            webXmlLastModified.remove(contextPath);
                            warLastModified.put
                                (files[i], Long.valueOf(dir.lastModified()));
                        }
                    }
                }
            }
        }

    
protected java.io.FileconfigBase()
Return a File object representing the "configuration root" directory for our associated Host.


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

        File file = new File(System.getProperty("catalina.base"), "conf");
        Container parent = host.getParent();
        if ((parent != null) && (parent instanceof Engine)) {
            file = new File(file, parent.getName());
        }
        file = new File(file, host.getName());
        try {
            configBase = file.getCanonicalFile();
        } catch (IOException e) {
            configBase = file;
        }
        return (configBase);

    
protected voiddeployApps()
Deploy applications for any directories or WAR files that are found in our "application root" directory.


        if (!(host instanceof Deployer))
            return;

        File appBase = appBase();
        if (!appBase.exists() || !appBase.isDirectory())
            return;
        File configBase = configBase();
        if (configBase.exists() && configBase.isDirectory()) {
            String configFiles[] = configBase.list();
            deployDescriptors(configBase, configFiles);
        }

        String files[] = appBase.list();
        deployWARs(appBase, files);
        deployDirectories(appBase, files);

    
protected voiddeployDescriptors(java.io.File configBase, java.lang.String[] files)
Deploy XML context descriptors.


        if (!deployXML)
           return;

        for (int i = 0; i < files.length; i++) {

            if (files[i].equalsIgnoreCase("META-INF"))
                continue;
            if (files[i].equalsIgnoreCase("WEB-INF"))
                continue;
            if (deployed.contains(files[i]))
                continue;
            File dir = new File(configBase, files[i]);
            if (files[i].toLowerCase().endsWith(".xml")) {

                deployed.add(files[i]);

                // Calculate the context path and make sure it is unique
                String file = files[i].substring(0, files[i].length() - 4);
                String contextPath = "/" + file.replace('_", '/");
                if (file.equals("ROOT")) {
                    contextPath = "";
                }

                // Assume this is a configuration descriptor and deploy it
                log.debug(sm.getString("hostConfig.deployDescriptor", files[i]));
                try {
                    if (host.findChild(contextPath) != null) {
                        if ((deployed.contains(file))
                            || (deployed.contains(file + ".war"))) {
                            // If this is a newly added context file and 
                            // it overrides a context with a simple path, 
                            // that was previously deployed by the auto
                            // deployer, undeploy the context
                            ((Deployer) host).remove(contextPath);
                        } else {
                            continue;
                        }
                    }
                    URL config =
                        new URL("file", null, dir.getCanonicalPath());
                    ((Deployer) host).install(config, null);
                } catch (Throwable t) {
                    log.error(sm.getString("hostConfig.deployDescriptor.error",
                                           files[i]), t);
                }

            }

        }

    
protected voiddeployDirectories(java.io.File appBase, java.lang.String[] files)
Deploy directories.


        for (int i = 0; i < files.length; i++) {

            if (files[i].equalsIgnoreCase("META-INF"))
                continue;
            if (files[i].equalsIgnoreCase("WEB-INF"))
                continue;
            if (deployed.contains(files[i]))
                continue;
            File dir = new File(appBase, files[i]);
            if (dir.isDirectory()) {

                deployed.add(files[i]);

                // Make sure there is an application configuration directory
                // This is needed if the Context appBase is the same as the
                // web server document root to make sure only web applications
                // are deployed and not directories for web space.
                File webInf = new File(dir, "/WEB-INF");
                if (!webInf.exists() || !webInf.isDirectory() ||
                    !webInf.canRead())
                    continue;

                // Calculate the context path and make sure it is unique
                String contextPath = "/" + files[i];
                if (files[i].equals("ROOT"))
                    contextPath = "";
                if (host.findChild(contextPath) != null)
                    continue;

                // Deploy the application in this directory
                if( log.isDebugEnabled() ) 
                    log.debug(sm.getString("hostConfig.deployDir", files[i]));
                long t1=System.currentTimeMillis();
                try {
                    URL url = new URL("file", null, dir.getCanonicalPath());
                    ((Deployer) host).install(contextPath, url);
                } catch (Throwable t) {
                    log.error(sm.getString("hostConfig.deployDir.error", files[i]),
                        t);
                }
                long t2=System.currentTimeMillis();
                if( (t2-t1) > 200 )
                    log.debug("Deployed " + files[i] + " " + (t2-t1));
            }

        }

    
protected voiddeployWARs(java.io.File appBase, java.lang.String[] files)
Deploy WAR files.


        for (int i = 0; i < files.length; i++) {

            if (files[i].equalsIgnoreCase("META-INF"))
                continue;
            if (files[i].equalsIgnoreCase("WEB-INF"))
                continue;
            if (deployed.contains(files[i]))
                continue;
            File dir = new File(appBase, files[i]);
            if (files[i].toLowerCase().endsWith(".war")) {

                deployed.add(files[i]);

                // Calculate the context path and make sure it is unique
                String contextPath = "/" + files[i];
                int period = contextPath.lastIndexOf(".");
                if (period >= 0)
                    contextPath = contextPath.substring(0, period);
                if (contextPath.equals("/ROOT"))
                    contextPath = "";
                if (host.findChild(contextPath) != null)
                    continue;

                // Checking for a nested /META-INF/context.xml
                JarFile jar = null;
                JarEntry entry = null;
                InputStream istream = null;
                BufferedOutputStream ostream = null;
                File xml = new File
                    (configBase, files[i].substring
                     (0, files[i].lastIndexOf(".")) + ".xml");
                if (!xml.exists()) {
                    try {
                        jar = new JarFile(dir);
                        entry = jar.getJarEntry("META-INF/context.xml");
                        if (entry != null) {
                            istream = jar.getInputStream(entry);
                            ostream =
                                new BufferedOutputStream
                                (new FileOutputStream(xml), 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;
                            entry = null;
                            jar.close();
                            jar = null;
                            deployDescriptors(configBase(), configBase.list());
                            return;
                        }
                    } catch (Exception e) {
                        // Ignore and continue
                        if (ostream != null) {
                            try {
                                ostream.close();
                            } catch (Throwable t) {
                                ;
                            }
                            ostream = null;
                        }
                        if (istream != null) {
                            try {
                                istream.close();
                            } catch (Throwable t) {
                                ;
                            }
                            istream = null;
                        }
                        entry = null;
                        if (jar != null) {
                            try {
                                jar.close();
                            } catch (Throwable t) {
                                ;
                            }
                            jar = null;
                        }
                    }
                }

                if (isUnpackWARs()) {

                    // Expand and deploy this application as a directory
                    log.debug(sm.getString("hostConfig.expand", files[i]));
                    URL url = null;
                    String path = null;
                    try {
                        url = new URL("jar:file:" +
                                      dir.getCanonicalPath() + "!/");
                        path = ExpandWar.expand(host, url);
                    } catch (IOException e) {
                        // JAR decompression failure
                        log.warn(sm.getString
                                 ("hostConfig.expand.error", files[i]));
                        continue;
                    } catch (Throwable t) {
                        log.error(sm.getString
                                  ("hostConfig.expand.error", files[i]), t);
                        continue;
                    }
                    try {
                        if (path != null) {
                            url = new URL("file:" + path);
                            ((Deployer) host).install(contextPath, url);
                        }
                    } catch (Throwable t) {
                        log.error(sm.getString
                                  ("hostConfig.expand.error", files[i]), t);
                    }

                } else {

                    // Deploy the application in this WAR file
                    log.info(sm.getString("hostConfig.deployJar", files[i]));
                    try {
                        URL url = new URL("file", null,
                                          dir.getCanonicalPath());
                        url = new URL("jar:" + url.toString() + "!/");
                        ((Deployer) host).install(contextPath, url);
                    } catch (Throwable t) {
                        log.error(sm.getString("hostConfig.deployJar.error",
                                         files[i]), t);
                    }

                }

            }

        }

    
protected java.lang.Stringexpand(java.net.URL war)
Expand the WAR file found at the specified URL into an unpacked directory structure, and return the absolute pathname to the expanded directory.

param
war URL of the web application archive to be expanded (must start with "jar:")
exception
IllegalArgumentException if this is not a "jar:" URL
exception
IOException if an input/output error was encountered during expansion


        return ExpandWar.expand(host,war);
    
protected voidexpand(java.io.InputStream input, java.io.File docBase, java.lang.String name)
Expand the specified input stream into the specified directory, creating a file named from the specified relative path.

param
input InputStream to be copied
param
docBase Document base directory into which we are expanding
param
name Relative pathname of the file to be created
exception
IOException if an input/output error occurs


        ExpandWar.expand(input,docBase,name);
    
public java.lang.StringgetConfigClass()
Return the Context configuration class name.



    // ------------------------------------------------------------- Properties


               
       

        return (this.configClass);

    
public java.lang.StringgetContextClass()
Return the Context implementation class name.


        return (this.contextClass);

    
public intgetDebug()
Return the debugging detail level for this component.


        return (this.debug);

    
public booleangetXmlNamespaceAware()
Get the server.xml attribute's xmlNamespaceAware.

return
true if namespace awarenes is enabled.

        return xmlNamespaceAware;
    
public booleangetXmlValidation()
Get the server.xml attribute's xmlValidation.

return
true if validation is enabled.

        return xmlValidation;
    
public booleanisDeployXML()
Return the deploy XML config file flag for this component.


        return (this.deployXML);

    
public booleanisUnpackWARs()
Return the unpack WARs flag.


        return (this.unpackWARs);

    
public voidlifecycleEvent(org.apache.catalina.LifecycleEvent event)
Process the START event for an associated Host.

param
event The lifecycle event that has occurred


        if (event.getType().equals("check"))
            check();

        // Identify the host we are associated with
        try {
            host = (Host) event.getLifecycle();
            if (host instanceof StandardHost) {
                int hostDebug = ((StandardHost) host).getDebug();
                if (hostDebug > this.debug) {
                    this.debug = hostDebug;
                }
                setDeployXML(((StandardHost) host).isDeployXML());
                setUnpackWARs(((StandardHost) host).isUnpackWARs());
                setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware());
                setXmlValidation(((StandardHost) host).getXmlValidation());
            }
        } catch (ClassCastException e) {
            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.START_EVENT))
            start();
        else if (event.getType().equals(Lifecycle.STOP_EVENT))
            stop();

    
protected voidlog(java.lang.String message)
Log a message on the Logger associated with our Host (if any)

param
message Message to be logged


        Logger logger = null;
        if (host != null)
            logger = host.getLogger();
        if (logger != null)
            logger.log("HostConfig[" + host.getName() + "]: " + message);
        else
            log.info(message);
    
protected voidlog(java.lang.String message, java.lang.Throwable throwable)
Log a message on the Logger associated with our Host (if any)

param
message Message to be logged
param
throwable Associated exception


        Logger logger = null;
        if (host != null)
            logger = host.getLogger();
        if (logger != null)
            logger.log("HostConfig[" + host.getName() + "] "
                       + message, throwable);
        else {
            log.error( message, throwable );
        }

    
protected booleanrestartContext(org.apache.catalina.Context context)

        boolean result = true;
        log.info("restartContext(" + context.getName() + ")");

        /*
        try {
            StandardContext sctx=(StandardContext)context;
            sctx.reload();
        } catch( Exception ex ) {
            log.warn("Erorr stopping context " + context.getName()  +  " " +
                    ex.toString());
        }
        */
        try {
            ((Lifecycle) context).stop();
        } catch( Exception ex ) {
            log.warn("Erorr stopping context " + context.getName()  +  " " +
                    ex.toString());
        }
        // if the context was not started ( for example an error in web.xml)
        // we'll still get to try to start
        try {
            ((Lifecycle) context).start();
        } catch (Exception e) {
            log.warn("Error restarting context " + context.getName() + " " +
                    e.toString());
            result = false;
        }
        
        return result;
    
public voidsetConfigClass(java.lang.String configClass)
Set the Context configuration class name.

param
configClass The new Context configuration class name.


        this.configClass = configClass;

    
public voidsetContextClass(java.lang.String contextClass)
Set the Context implementation class name.

param
contextClass The new Context implementation class name.


        this.contextClass = contextClass;

    
public voidsetDebug(int debug)
Set the debugging detail level for this component.

param
debug The new debugging detail level


        this.debug = debug;

    
public voidsetDeployXML(boolean deployXML)
Set the deploy XML config file flag for this component.

param
deployXML The new deploy XML flag


        this.deployXML= deployXML;

    
public voidsetUnpackWARs(boolean unpackWARs)
Set the unpack WARs flag.

param
unpackWARs The new unpack WARs flag


        this.unpackWARs = unpackWARs;

    
public voidsetXmlNamespaceAware(boolean xmlNamespaceAware)
Set the namespace aware feature of the XML parser used when parsing xml instances.

param
xmlNamespaceAware true to enable namespace awareness

        this.xmlNamespaceAware=xmlNamespaceAware;
    
public voidsetXmlValidation(boolean xmlValidation)
Set the validation feature of the XML parser used when parsing xml instances.

param
xmlValidation true to enable xml instance validation

        this.xmlValidation = xmlValidation;
    
public voidstart()
Process a "start" event for this Host.


        if (log.isDebugEnabled())
            log.debug(sm.getString("hostConfig.start"));

        if (host.getDeployOnStartup()) {
            deployApps();
        } else {
            // Deploy descriptors anyway (it should be equivalent to being
            // part of server.xml)
            File configBase = configBase();
            if (configBase.exists() && configBase.isDirectory()) {
                String configFiles[] = configBase.list();
                deployDescriptors(configBase, configFiles);
            }
        } 

    
public voidstop()
Process a "stop" event for this Host.


        if (log.isDebugEnabled())
            log.debug(sm.getString("hostConfig.stop"));

        undeployApps();

        appBase = null;
        configBase = null;

    
protected voidundeployApps()
Undeploy all deployed applications.


        if (!(host instanceof Deployer))
            return;
        if (log.isDebugEnabled())
            log.debug(sm.getString("hostConfig.undeploying"));

        String contextPaths[] = ((Deployer) host).findDeployedApps();
        for (int i = 0; i < contextPaths.length; i++) {
            if (log.isDebugEnabled())
                log.debug(sm.getString("hostConfig.undeploy", contextPaths[i]));
            try {
                ((Deployer) host).remove(contextPaths[i]);
            } catch (Throwable t) {
                log.error(sm.getString("hostConfig.undeploy.error",
                                 contextPaths[i]), t);
            }
        }

        webXmlLastModified.clear();
        deployed.clear();