You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by rw...@apache.org on 2011/04/29 03:19:12 UTC

svn commit: r1097667 - /geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java

Author: rwonly
Date: Fri Apr 29 01:19:12 2011
New Revision: 1097667

URL: http://svn.apache.org/viewvc?rev=1097667&view=rev
Log:
GERONIMO-5832 remove the un-relative ids from toRemove list after its traversal, and don't react the events that hot-deployer generates to avoid the deletion of the new file during file update action

Modified:
    geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java

Modified: geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java?rev=1097667&r1=1097666&r2=1097667&view=diff
==============================================================================
--- geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java (original)
+++ geronimo/server/trunk/plugins/hotdeploy/geronimo-hot-deploy/src/main/java/org/apache/geronimo/deployment/hot/DirectoryMonitor.java Fri Apr 29 01:19:12 2011
@@ -31,7 +31,6 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.geronimo.deployment.cli.DeployUtils;
 import org.apache.geronimo.kernel.repository.Artifact;
@@ -123,7 +122,8 @@ public class DirectoryMonitor implements
     private boolean done = false;
     private Listener listener; // a little cheesy, but do we really need multiple listeners?
     private final Map<String, FileInfo> files;
-    private final CopyOnWriteArrayList <Artifact> toRemove = new CopyOnWriteArrayList <Artifact>();
+    private volatile String workingOnConfigId;
+    private final ArrayList <Artifact> toRemove = new ArrayList <Artifact>();
     private File monitorFile;
 
     public DirectoryMonitor(File directory, Listener listener, int pollIntervalMillis) {
@@ -179,29 +179,49 @@ public class DirectoryMonitor implements
         this.done = true;
     }
 
+    // The undeployed operation could occur in this hot-deploy thread or in console/cli.
+    // The id that go to "toRemove" should be the ones that not undeployed in this hot-deploy thread 
+    // BTW, now we support EBA deployment. And if an EBA includes a WAB, which also has a configuration id during EBA deployment, 
+    // this method also can be called with the WAB id. And the WAB' so id will also go into the "toRemove" list.
     public void removeModuleId(Artifact id) {
-        log.info("Hot deployer notified that an artifact was removed: "+id);
-        toRemove.add(id);
+        log.info("Hot deployer notified that an artifact was undeployed: "+id);
+        if(id.toString().equals(workingOnConfigId)) {
+            // don't react to undelpoy events we generated ourselves
+            // because the file update action(i.e. redeploy) will cause the old module to undeploy first
+            // we must handle this so that its config id won't go "toRemove" list to avoid the deletion of the new file.
+            return; 
+        }
+        synchronized (toRemove) {
+            toRemove.add(id);
+        }
     }
 
     private void doRemoves() {
-        synchronized (files) {
-            for (Artifact id : toRemove) {
-                for (Iterator<String> filesItr = files.keySet().iterator(); filesItr.hasNext();) {
-                    String path = filesItr.next();
-                    FileInfo info = files.get(path);
-                    Artifact target = Artifact.create(info.getConfigId());
-                    if (id.matches(target)) { // need to remove record & delete file
-                        File file = new File(path);
-                        if (file.exists()) { // if not, probably it's deletion kicked off this whole process
-                            log.info("Hot deployer deleting " + id);
-                            if (!FileUtils.recursiveDelete(file)) {
-                                log.error("Hot deployer unable to delete " + path);
+        synchronized (toRemove) {
+            synchronized (files) {
+                for (Iterator<Artifact> idItr = toRemove.iterator(); idItr.hasNext();) {
+                    Artifact id = idItr.next();
+                    for (Iterator<String> filesItr = files.keySet().iterator(); filesItr.hasNext();) {
+                        String path = filesItr.next();
+                        FileInfo info = files.get(path);
+                        if (info.getConfigId() == null){
+                            // the file is new added, have not deployed yet, so its config id is not set.
+                            continue;
+                        }
+                        Artifact target = Artifact.create(info.getConfigId());
+                        if (id.matches(target)) { // need to remove record & delete file
+                            File file = new File(path);
+                            if (file.exists()) {  // if not, probably it's deletion kicked off this whole process
+                                log.info("Hot deployer deleting " + id);
+                                if (!FileUtils.recursiveDelete(file)) {
+                                    log.error("Hot deployer unable to delete " + path);
+                                }
+                                filesItr.remove();
                             }
-                            filesItr.remove();
-                            toRemove.remove(id);
                         }
                     }
+                    // remove the id form the toRemove list no matter if we found it in the "files" list
+                    idItr.remove();
                 }
             }
         }
@@ -277,6 +297,7 @@ public class DirectoryMonitor implements
                             initialize();
                             listener.started();
                         } else {
+                            doRemoves();
                             scanDirectory();
                         }
                     }
@@ -318,7 +339,6 @@ public class DirectoryMonitor implements
      * Looks for changes to the immediate contents of the directory we're watching.
      */
     private void scanDirectory() {
-        doRemoves();
         File parent = directory;
         File[] children = parent.listFiles();
         if (!directory.exists() || children == null) {
@@ -339,42 +359,44 @@ public class DirectoryMonitor implements
                     continue;
                 }
                 FileInfo now = child.isDirectory() ? getDirectoryInfo(child) : getFileInfo(child);
-                FileInfo then = files.get(now.getPath());
-                if (then == null) { // Brand new, wait a bit to make sure it's not still changing
+                FileInfo last = files.get(now.getPath());
+                if (last == null) { // Brand new, wait a bit to make sure it's not still changing
                     now.setNewFile(true);
                     files.put(now.getPath(), now);
                     changeMade = true;
                     log.debug("New File: " + now.getPath());
                 } else {
-                    oldList.remove(then.getPath());
-                    if (now.isSame(then)) { // File is the same as the last time we scanned it
-                        if (then.isChanging()) {
+                    oldList.remove(last.getPath());
+                    if (now.isSame(last)) { // File is the same as the last time we scanned it
+                        if (last.isChanging()) { // else it's just totally unchanged and we ignore it this pass
                             log.debug("File finished changing: " + now.getPath());
                             // Used to be changing, now in (hopefully) its final state
-                            if (then.isNewFile()) {
-                                actions.add(new FileAction(FileAction.NEW_FILE, child, then));
+                            if (last.isNewFile()) {
+                                actions.add(new FileAction(FileAction.NEW_FILE, child, last));
                             } else {
-                                actions.add(new FileAction(FileAction.UPDATED_FILE, child, then));
+                                actions.add(new FileAction(FileAction.UPDATED_FILE, child, last));
                             }
-                            then.setChanging(false);
-                        } // else it's just totally unchanged and we ignore it this pass
-                    } else if(then.isNewFile() || now.getModified() > then.getModified()) {
-                        // The two records are different -- record the latest as a file that's changing
-                        // and later when it stops changing we'll do the add or update as appropriate.
-                        now.setConfigId(then.getConfigId());
-                        now.setNewFile(then.isNewFile());
+                            last.setChanging(false);
+                        } 
+                    } else { // is changing, when finish will do the file action accordingly
+                        if (last.isNewFile()){ // is adding file
+                            now.setNewFile(last.isNewFile());
+                        } else { // is replacing file
+                            now.setConfigId(last.getConfigId());
+                        }
                         files.put(now.getPath(), now);
                         changeMade = true;
                         log.debug("File Changed: " + now.getPath());
                     }
                 }
             }
+            
             // Look for any files we used to know about but didn't find in this pass
             for (Iterator<String> it = oldList.iterator(); it.hasNext();) {
                 String name = it.next();
                 FileInfo info = files.get(name);
                 log.debug("File removed: " + name);
-                if (info.isNewFile()) { // Was never added, just whack it
+                if (info.isNewFile()) { // was never deployed, just drop it
                     files.remove(name);
                     changeMade = true;
                 } else {
@@ -396,13 +418,15 @@ public class DirectoryMonitor implements
                 FileAction action = it.next();
                 try {
                     if (action.action == FileAction.REMOVED_FILE) {
+                        workingOnConfigId = action.info.getConfigId();
                         if (action.info.getConfigId() == null || listener.fileRemoved(action.child, action.info.getConfigId())) {
                             files.remove(action.child.getPath());
                             changeMade = true;
                         }
+                        workingOnConfigId = null;
                     } else if (action.action == FileAction.NEW_FILE) {
                         if (listener.isFileDeployed(action.child, calculateModuleId(action.child))) {
-                            String workingOnConfigId = calculateModuleId(action.child);
+                            workingOnConfigId = calculateModuleId(action.child);
                             String result = listener.fileUpdated(action.child, workingOnConfigId);
                             if (result != null) {
                                 if (!result.equals("")) {
@@ -414,8 +438,15 @@ public class DirectoryMonitor implements
                             // remove the previous jar or directory if duplicate
                             File[] childs = directory.listFiles();
                             for (int i = 0; i < childs.length; i++) {
-                                String path = childs[i].getAbsolutePath();
-                                String configId = (files.get(path)).configId;
+                                File child = children[i];
+                                if (!child.canRead()) {
+                                    continue;
+                                }
+                                if (child.equals(monitorFile)) {
+                                    continue;
+                                }
+                                String path = child.getAbsolutePath();
+                                String configId = files.get(path).getConfigId();
                                 if (configId != null && configId.equals(workingOnConfigId) && !action.child.getAbsolutePath().equals(path)) {
                                     File fd = new File(path);
                                     if (fd.isDirectory()) {
@@ -449,6 +480,7 @@ public class DirectoryMonitor implements
                         action.info.setNewFile(false);
                         changeMade = true;
                     } else if (action.action == FileAction.UPDATED_FILE) {
+                        workingOnConfigId = action.info.getConfigId();
                         String result = listener.fileUpdated(action.child, action.info.getConfigId());
                         FileInfo update = action.info;
                         if (result != null) {
@@ -458,6 +490,7 @@ public class DirectoryMonitor implements
                                 update.setConfigId(calculateModuleId(action.child));
                             }
                         }
+                        workingOnConfigId = null;
                     }
                 } catch (Exception e) {
                     log.error("Unable to " + action.getActionName() + " file " + action.child.getAbsolutePath(), e);