You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/04/01 19:05:16 UTC

svn commit: r1670730 - /tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java

Author: markt
Date: Wed Apr  1 17:05:16 2015
New Revision: 1670730

URL: http://svn.apache.org/r1670730
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=57772
When reloading an application and a DIR representing an expanded WAR needs to be deleted ensure that the DIR is deleted after the context has been stopped rather than before.

Modified:
    tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java

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=1670730&r1=1670729&r2=1670730&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java Wed Apr  1 17:05:16 2015
@@ -1264,12 +1264,10 @@ public class HostConfig implements Lifec
                                 docBaseFile = new File(host.getAppBaseFile(),
                                         docBase);
                             }
-                            ExpandWar.delete(docBaseFile);
-                            // Reset the docBase to trigger re-expansion of the
-                            // WAR
-                            context.setDocBase(resource.getAbsolutePath());
+                            reload(app, docBaseFile, resource.getAbsolutePath());
+                        } else {
+                            reload(app, null, null);
                         }
-                        reload(app);
                         // Update times
                         app.redeployResources.put(resources[i],
                                 Long.valueOf(resource.lastModified()));
@@ -1331,7 +1329,7 @@ public class HostConfig implements Lifec
                     update) {
                 if (!update) {
                     // Reload application
-                    reload(app);
+                    reload(app, null, null);
                     update = true;
                 }
                 // Update times. More than one file may have been updated. We
@@ -1344,16 +1342,28 @@ public class HostConfig implements Lifec
     }
 
 
-    private void reload(DeployedApplication app) {
+    /*
+     * Note: If either of fileToRemove and newDocBase are null, both will be
+     *       ignored.
+     */
+    private void reload(DeployedApplication app, File fileToRemove, String newDocBase) {
         if(log.isInfoEnabled())
             log.info(sm.getString("hostConfig.reload", app.name));
         Context context = (Context) host.findChild(app.name);
         if (context.getState().isAvailable()) {
+            if (fileToRemove != null && newDocBase != null) {
+                context.addLifecycleListener(
+                        new ExpandedDirectoryRemovalListener(fileToRemove, newDocBase));
+            }
             // Reload catches and logs exceptions
             context.reload();
         } else {
             // If the context was not started (for example an error
             // in web.xml) we'll still get to try to start
+            if (fileToRemove != null && newDocBase != null) {
+                ExpandWar.delete(fileToRemove);
+                context.setDocBase(newDocBase);
+            }
             try {
                 context.start();
             } catch (Exception e) {
@@ -1772,4 +1782,54 @@ public class HostConfig implements Lifec
             config.deployDirectory(cn, dir);
         }
     }
+
+
+    /*
+     * The purpose of this class is to provide a way for HostConfig to get
+     * a Context to delete an expanded WAR after the Context stops. This is to
+     * resolve this issue described in Bug 57772. The alternative solutions
+     * require either duplicating a lot of the Context.reload() code in
+     * HostConfig or adding a new reload(boolean) method to Context that allows
+     * the caller to optionally delete any expanded WAR.
+     *
+     * The LifecycleListener approach offers greater flexibility and enables the
+     * behaviour to be changed / extended / removed in future without changing
+     * the Context API.
+     */
+    private static class ExpandedDirectoryRemovalListener implements LifecycleListener {
+
+        private final File toDelete;
+        private final String newDocBase;
+
+        /**
+         * Create a listener that will ensure that any expanded WAR is removed
+         * and the docBase set to the specified WAR.
+         *
+         * @param toDelete The file (a directory representing an expanded WAR)
+         *                 to be deleted
+         * @param newDocBase The new docBase for the Context
+         */
+        public ExpandedDirectoryRemovalListener(File toDelete, String newDocBase) {
+            this.toDelete = toDelete;
+            this.newDocBase = newDocBase;
+        }
+
+        @Override
+        public void lifecycleEvent(LifecycleEvent event) {
+            if (event.getType() == Lifecycle.AFTER_STOP_EVENT) {
+                // The context has stopped.
+                Context context = (Context) event.getLifecycle();
+
+                // Remove the old expanded WAR.
+                ExpandWar.delete(toDelete);
+
+                // Reset the docBase to trigger re-expansion of the WAR.
+                context.setDocBase(newDocBase);
+
+                // Remove this listener from the Context else it will run every
+                // time the Context is stopped.
+                context.removeLifecycleListener(this);
+            }
+        }
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org