Author: markt Date: Sat Sep 8 21:00:32 2012 New Revision: 1382366 URL: http://svn.apache.org/viewvc?rev=1382366&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=52777 Implement optional automatic removal of old applications where parallel deployment has been used.
Modified: tomcat/trunk/java/org/apache/catalina/Host.java tomcat/trunk/java/org/apache/catalina/core/StandardHost.java tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/startup/mbeans-descriptors.xml tomcat/trunk/webapps/docs/config/context.xml tomcat/trunk/webapps/docs/config/host.xml Modified: tomcat/trunk/java/org/apache/catalina/Host.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Host.java?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Host.java (original) +++ tomcat/trunk/java/org/apache/catalina/Host.java Sat Sep 8 21:00:32 2012 @@ -210,6 +210,22 @@ public interface Host extends Container public void setCreateDirs(boolean createDirs); + /** + * Returns true of the Host is configured to automatically undeploy old + * versions of applications deployed using parallel deployment. This only + * takes effect is {@link #getAutoDeploy()} also returns true. + */ + public boolean getUndeployOldVersions(); + + + /** + * Set to true if the Host should automatically undeploy old versions of + * applications deployed using parallel deployment. This only takes effect + * if {@link #getAutoDeploy()} returns true. + */ + public void setUndeployOldVersions(boolean undeployOldVersions); + + // --------------------------------------------------------- Public Methods /** Modified: tomcat/trunk/java/org/apache/catalina/core/StandardHost.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardHost.java?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardHost.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardHost.java Sat Sep 8 21:00:32 2012 @@ -181,9 +181,24 @@ public class StandardHost extends Contai private Pattern deployIgnore = null; + private boolean undeployOldVersions = false; + + // ------------------------------------------------------------- Properties @Override + public boolean getUndeployOldVersions() { + return undeployOldVersions; + } + + + @Override + public void setUndeployOldVersions(boolean undeployOldVersions) { + this.undeployOldVersions = undeployOldVersions; + } + + + @Override public ExecutorService getStartStopExecutor() { return startStopExecutor; } Modified: tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml (original) +++ tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml Sat Sep 8 21:00:32 2012 @@ -1181,6 +1181,10 @@ type="java.lang.String" writeable="false"/> + <attribute name="undeployOldVersions" + description="Determines if old versions of applications deployed using parallel deployment are automatically undeployed when no longer used. Requires autoDeploy to be enabled." + type="boolean"/> + <attribute name="unpackWARs" description="Unpack WARs property" is="true" Modified: tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java Sat Sep 8 21:00:32 2012 @@ -27,11 +27,14 @@ import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -48,6 +51,7 @@ import org.apache.catalina.Host; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Manager; import org.apache.catalina.core.StandardHost; import org.apache.catalina.util.ContextName; import org.apache.catalina.util.IOTools; @@ -1163,43 +1167,7 @@ public class HostConfig if ((!resource.isDirectory()) && resource.lastModified() > lastModified) { // Undeploy application - if (log.isInfoEnabled()) - log.info(sm.getString("hostConfig.undeploy", app.name)); - Container context = host.findChild(app.name); - try { - host.removeChild(context); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - log.warn(sm.getString - ("hostConfig.context.remove", app.name), t); - } - // Delete other redeploy resources - for (int j = i + 1; j < resources.length; j++) { - try { - File current = new File(resources[j]); - current = current.getCanonicalFile(); - // Never delete per host context.xml defaults - if (Constants.HostContextXml.equals( - current.getName())) { - continue; - } - // Only delete resources in the appBase or the - // host's configBase - if ((current.getAbsolutePath().startsWith( - host.getAppBaseFile().getAbsolutePath() + - File.separator)) - || (current.getAbsolutePath().startsWith( - host.getConfigBaseFile().getAbsolutePath()))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - deployed.remove(app.name); + deleteRedeployResources(app, resources, i, false); return; } } else { @@ -1220,71 +1188,7 @@ public class HostConfig continue; } // Undeploy application - if (log.isInfoEnabled()) - log.info(sm.getString("hostConfig.undeploy", app.name)); - Container context = host.findChild(app.name); - try { - host.removeChild(context); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - log.warn(sm.getString - ("hostConfig.context.remove", app.name), t); - } - // Delete all redeploy resources - for (int j = i + 1; j < resources.length; j++) { - try { - File current = new File(resources[j]); - current = current.getCanonicalFile(); - // Never delete per host context.xml defaults - if (Constants.HostContextXml.equals( - current.getName())) { - continue; - } - // Only delete resources in the appBase or the host's - // configBase - if ((current.getAbsolutePath().startsWith( - host.getAppBaseFile().getAbsolutePath() + File.separator)) - || (current.getAbsolutePath().startsWith( - host.getConfigBaseFile().getAbsolutePath()))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - // Delete reload resources as well (to remove any remaining .xml - // descriptor) - String[] resources2 = - app.reloadResources.keySet().toArray(new String[0]); - for (int j = 0; j < resources2.length; j++) { - try { - File current = new File(resources2[j]); - current = current.getCanonicalFile(); - // Never delete per host context.xml defaults - if (Constants.HostContextXml.equals( - current.getName())) { - continue; - } - // Only delete resources in the appBase or the host's - // configBase - if ((current.getAbsolutePath().startsWith( - host.getAppBaseFile().getAbsolutePath() + File.separator)) - || ((current.getAbsolutePath().startsWith( - host.getConfigBaseFile().getAbsolutePath()) - && (current.getAbsolutePath().endsWith(".xml"))))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - deployed.remove(app.name); + deleteRedeployResources(app, resources, i, true); return; } } @@ -1325,6 +1229,81 @@ public class HostConfig } + private void deleteRedeployResources(DeployedApplication app, + String[] resources, int i, boolean deleteReloadResources) { + + // Delete redeploy resources + if (log.isInfoEnabled()) + log.info(sm.getString("hostConfig.undeploy", app.name)); + Container context = host.findChild(app.name); + try { + host.removeChild(context); + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + log.warn(sm.getString + ("hostConfig.context.remove", app.name), t); + } + // Delete other redeploy resources + for (int j = i + 1; j < resources.length; j++) { + try { + File current = new File(resources[j]); + current = current.getCanonicalFile(); + // Never delete per host context.xml defaults + if (Constants.HostContextXml.equals( + current.getName())) { + continue; + } + // Only delete resources in the appBase or the + // host's configBase + if ((current.getAbsolutePath().startsWith( + host.getAppBaseFile().getAbsolutePath() + + File.separator)) + || (current.getAbsolutePath().startsWith( + host.getConfigBaseFile().getAbsolutePath()))) { + if (log.isDebugEnabled()) + log.debug("Delete " + current); + ExpandWar.delete(current); + } + } catch (IOException e) { + log.warn(sm.getString + ("hostConfig.canonicalizing", app.name), e); + } + } + + // Delete reload resources (to remove any remaining .xml descriptor) + if (deleteReloadResources) { + String[] resources2 = + app.reloadResources.keySet().toArray(new String[0]); + for (int j = 0; j < resources2.length; j++) { + try { + File current = new File(resources2[j]); + current = current.getCanonicalFile(); + // Never delete per host context.xml defaults + if (Constants.HostContextXml.equals( + current.getName())) { + continue; + } + // Only delete resources in the appBase or the host's + // configBase + if ((current.getAbsolutePath().startsWith( + host.getAppBaseFile().getAbsolutePath() + File.separator)) + || ((current.getAbsolutePath().startsWith( + host.getConfigBaseFile().getAbsolutePath()) + && (current.getAbsolutePath().endsWith(".xml"))))) { + if (log.isDebugEnabled()) + log.debug("Delete " + current); + ExpandWar.delete(current); + } + } catch (IOException e) { + log.warn(sm.getString + ("hostConfig.canonicalizing", app.name), e); + } + } + + } + deployed.remove(app.name); + } + /** * Process a "start" event for this Host. */ @@ -1397,10 +1376,15 @@ public class HostConfig if (!isServiced(apps[i].name)) checkResources(apps[i]); } + + // Check for old versions of applications that can now be undeployed + if (host.getUndeployOldVersions()) { + checkUndeploy(); + } + // Hotdeploy applications deployApps(); } - } @@ -1417,6 +1401,52 @@ public class HostConfig } /** + * Check for old versions of applications using parallel deployment that are + * now unused (have no active sessions) and undeploy any that are found. + */ + public void checkUndeploy() { + // Need ordered set of names + SortedSet<String> sortedAppNames = new TreeSet<>(); + sortedAppNames.addAll(deployed.keySet()); + + if (sortedAppNames.size() < 2) { + return; + } + Iterator<String> iter = sortedAppNames.iterator(); + + ContextName previous = new ContextName(iter.next()); + do { + ContextName current = new ContextName(iter.next()); + + if (current.getPath().equals(previous.getPath())) { + // Current and previous are same version - current will always + // be a later version + Context context = (Context) host.findChild(previous.getName()); + if (context != null) { + Manager manager = context.getManager(); + if (manager != null && manager.getActiveSessions() == 0) { + if (log.isInfoEnabled()) { + log.info(sm.getString("hostConfig.undeployVersion", + previous.getName())); + } + DeployedApplication app = + deployed.get(previous.getName()); + String[] resources = + app.redeployResources.keySet().toArray( + new String[0]); + // Version is unused - undeploy it completely + // The -1 is a 'trick' to ensure all redeploy resources + // are removed + deleteRedeployResources(app, resources, -1, + true); + } + } + } + previous = current; + } while (iter.hasNext()); + } + + /** * Add a new Context to be managed by us. * Entry point for the admin webapp, and other JMX Context controllers. */ Modified: tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties Sat Sep 8 21:00:32 2012 @@ -104,6 +104,7 @@ hostConfig.reload=Reloading context [{0} hostConfig.start=HostConfig: Processing START hostConfig.stop=HostConfig: Processing STOP hostConfig.undeploy=Undeploying context [{0}] +hostConfig.undeployVersion=Undeploying old version of context [{0}] which has no active session tldConfig.addListeners=Adding {0} listeners from TLD files tldConfig.cce=Lifecycle event data object {0} is not a Context tldConfig.dirFail=Failed to process directory [{0}] for TLD files Modified: tomcat/trunk/java/org/apache/catalina/startup/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/mbeans-descriptors.xml?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/mbeans-descriptors.xml (original) +++ tomcat/trunk/java/org/apache/catalina/startup/mbeans-descriptors.xml Sat Sep 8 21:00:32 2012 @@ -109,6 +109,12 @@ type="java.lang.String"/> </operation> + <operation name="checkUndeploy" + description="Undeploy any old versions of applications deployed using parallel deployment that have no active sessions" + impact="ACTION" + returnType="void"> + </operation> + <operation name="getDeploymentTime" description="Get the instant where an application was deployed" impact="ACTION" Modified: tomcat/trunk/webapps/docs/config/context.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/context.xml (original) +++ tomcat/trunk/webapps/docs/config/context.xml Sat Sep 8 21:00:32 2012 @@ -82,6 +82,9 @@ <li>If session information is present in the request but no matching session can be found, use the latest version.</li> </ul> + <p>The <a href="host.html">Host</a> may be configured (via the + <code>undeployOldVersions</code>) to remove old versions deployed in this way + once they are no longer in use.</p> </subsection> <subsection name="Naming"> Modified: tomcat/trunk/webapps/docs/config/host.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/host.xml?rev=1382366&r1=1382365&r2=1382366&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/host.xml (original) +++ tomcat/trunk/webapps/docs/config/host.xml Sat Sep 8 21:00:32 2012 @@ -201,6 +201,14 @@ not specified, the default value of 1 will be used.</p> </attribute> + <attribute name="undeployOldVersions" required="false"> + <p>This flag determines if Tomcat, as part of the auto deployment + process, will check for old, unused versions of web applications + deployed using parallel deployment and, if any are found, remove them. + This flag only applies if <code>autoDeploy</code> is true. If not + specified the default value of false will be used.</p> + </attribute> + </attributes> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org