Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2011-04-01 02:18:18 +0000
committerGreg Wilkins2011-04-01 02:18:18 +0000
commit1bd0adabfb01a3def0303d86668d07fd5f11623f (patch)
tree7f09d4407982b17a3c61c14cac9f927ee694e739
parent548f6bac5aa8f2f45c398c7ad526fb03c2c074ee (diff)
downloadorg.eclipse.jetty.project-1bd0adabfb01a3def0303d86668d07fd5f11623f.tar.gz
org.eclipse.jetty.project-1bd0adabfb01a3def0303d86668d07fd5f11623f.tar.xz
org.eclipse.jetty.project-1bd0adabfb01a3def0303d86668d07fd5f11623f.zip
340949 Scanner delays file notifications until files are stable
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2948 7e9141cc-0065-0410-87d8-b60c137991c4
-rw-r--r--VERSION.txt1
-rw-r--r--jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java2
-rw-r--r--jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java4
-rw-r--r--jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyMonitor.java6
-rw-r--r--jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyMonitorTest.java1
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java163
6 files changed, 135 insertions, 42 deletions
diff --git a/VERSION.txt b/VERSION.txt
index bde2b54903..e6629b0fc7 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -10,6 +10,7 @@ jetty-7.3.2-SNAPSHOT
+ 340838 Update ConnectHandler to perform half closes properly
+ 340878 Integrations should be able to load their own keystores
+ 340920 Dynamically assign RMI registry port for integration testing
+ + 340949 Scanner delays file notifications until files are stable
+ 341006 Move inner enums out into separate file
+ 341105 Stack trace is printed for an ignored exception
+ 341145 WebAppContext MBean attribute serverClasses returns empty value
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
index fee9e6fe88..0b645d6fd5 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ExpireTest.java
@@ -16,6 +16,7 @@ package org.eclipse.jetty.client;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -60,7 +61,6 @@ public class ExpireTest
}
catch (InterruptedException x)
{
- throw new ServletException(x);
}
}
});
diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java
index 0f2e562f15..8e6357bd43 100644
--- a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java
+++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/providers/WebAppProviderTest.java
@@ -13,8 +13,8 @@ import org.junit.Test;
public class WebAppProviderTest
{
- @Rule
- public TestingDir testdir = new TestingDir();
+ @Rule
+ public TestingDir testdir = new TestingDir();
private static XmlConfiguredJetty jetty;
@Before
diff --git a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyMonitor.java b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyMonitor.java
index 93cf4b7182..64a1755fec 100644
--- a/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyMonitor.java
+++ b/jetty-policy/src/main/java/org/eclipse/jetty/policy/PolicyMonitor.java
@@ -40,7 +40,7 @@ public abstract class PolicyMonitor extends AbstractLifeCycle
/**
* scan interval in seconds for policy file changes
*/
- private int _scanInterval = 10;
+ private int _scanInterval = 1;
/**
* specialized listener enabling waitForScan() functionality
@@ -72,6 +72,7 @@ public abstract class PolicyMonitor extends AbstractLifeCycle
*/
public PolicyMonitor( String directory )
{
+ this();
_policyDirectory = directory;
}
@@ -144,7 +145,8 @@ public abstract class PolicyMonitor extends AbstractLifeCycle
*/
public synchronized void waitForScan() throws Exception
{
- CountDownLatch latch = new CountDownLatch(1);
+ // wait for 2 scans for stable files
+ CountDownLatch latch = new CountDownLatch(2);
_scanningListener.setScanningLatch(latch);
_scanner.scan();
diff --git a/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyMonitorTest.java b/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyMonitorTest.java
index 0c16fe5c65..8174d61c06 100644
--- a/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyMonitorTest.java
+++ b/jetty-policy/src/test/java/org/eclipse/jetty/policy/PolicyMonitorTest.java
@@ -36,6 +36,7 @@ public class PolicyMonitorTest
count.incrementAndGet();
}
};
+ monitor.setScanInterval(1);
monitor.start();
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
index 9456299f4e..08e030815b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java
@@ -29,6 +29,7 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
@@ -38,16 +39,15 @@ import org.eclipse.jetty.util.log.Log;
* Utility for scanning a directory for added, removed and changed
* files and reporting these events via registered Listeners.
*
- * TODO AbstractLifeCycle
*/
-public class Scanner
+public class Scanner extends AbstractLifeCycle
{
private static int __scannerId=0;
private int _scanInterval;
private int _scanCount = 0;
private final List<Listener> _listeners = new ArrayList<Listener>();
- private final Map<String,Long> _prevScan = new HashMap<String,Long> ();
- private final Map<String,Long> _currentScan = new HashMap<String,Long> ();
+ private final Map<String,TimeNSize> _prevScan = new HashMap<String,TimeNSize> ();
+ private final Map<String,TimeNSize> _currentScan = new HashMap<String,TimeNSize> ();
private FilenameFilter _filter;
private final List<File> _scanDirs = new ArrayList<File>();
private volatile boolean _running = false;
@@ -56,8 +56,45 @@ public class Scanner
private Timer _timer;
private TimerTask _task;
private int _scanDepth=0;
+
+ public enum Notification { ADDED, CHANGED, REMOVED };
+ private final Map<String,Notification> _notifications = new HashMap<String,Notification>();
-
+ static class TimeNSize
+ {
+ final long _lastModified;
+ final long _size;
+
+ public TimeNSize(long lastModified, long size)
+ {
+ _lastModified = lastModified;
+ _size = size;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return (int)_lastModified^(int)_size;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o instanceof TimeNSize)
+ {
+ TimeNSize tns = (TimeNSize)o;
+ return tns._lastModified==_lastModified && tns._size==_size;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "[lm="+_lastModified+",s="+_size+"]";
+ }
+ }
+
/**
* Listener
*
@@ -274,7 +311,7 @@ public class Scanner
/**
* Start the scanning action.
*/
- public synchronized void start ()
+ public synchronized void doStart()
{
if (_running)
return;
@@ -285,6 +322,7 @@ public class Scanner
{
// if files exist at startup, report them
scan();
+ scan(); // scan twice so files reported as stable
}
else
{
@@ -321,14 +359,14 @@ public class Scanner
{
_timer = newTimer();
_task = newTimerTask();
- _timer.schedule(_task, 1000L*getScanInterval(),1000L*getScanInterval());
+ _timer.schedule(_task, 1010L*getScanInterval(),1010L*getScanInterval());
}
}
}
/**
* Stop the scanning.
*/
- public synchronized void stop ()
+ public synchronized void doStop()
{
if (_running)
{
@@ -388,45 +426,97 @@ public class Scanner
* @param currentScan the info from the most recent pass
* @param oldScan info from the previous pass
*/
- public void reportDifferences (Map<String,Long> currentScan, Map<String,Long> oldScan)
+ public synchronized void reportDifferences (Map<String,TimeNSize> currentScan, Map<String,TimeNSize> oldScan)
{
- List<String> bulkChanges = new ArrayList<String>();
-
+ // scan the differences and add what was found to the map of notifications:
+
Set<String> oldScanKeys = new HashSet<String>(oldScan.keySet());
- Iterator<Entry<String, Long>> itor = currentScan.entrySet().iterator();
- while (itor.hasNext())
+
+ // Look for new and changed files
+ for (Map.Entry<String, TimeNSize> entry: currentScan.entrySet())
{
- Map.Entry<String, Long> entry = itor.next();
- if (!oldScanKeys.contains(entry.getKey()))
+ String file = entry.getKey();
+ if (!oldScanKeys.contains(file))
{
- Log.debug("File added: "+entry.getKey());
- reportAddition ((String)entry.getKey());
- bulkChanges.add(entry.getKey());
+ Notification old=_notifications.put(file,Notification.ADDED);
+ if (old!=null)
+ {
+ switch(old)
+ {
+ case REMOVED:
+ case CHANGED:
+ _notifications.put(file,Notification.CHANGED);
+ }
+ }
}
- else if (!oldScan.get(entry.getKey()).equals(entry.getValue()))
+ else if (!oldScan.get(file).equals(currentScan.get(file)))
{
- Log.debug("File changed: "+entry.getKey());
- reportChange((String)entry.getKey());
- oldScanKeys.remove(entry.getKey());
- bulkChanges.add(entry.getKey());
+ Notification old=_notifications.put(file,Notification.CHANGED);
+ if (old!=null)
+ {
+ switch(old)
+ {
+ case ADDED:
+ _notifications.put(file,Notification.ADDED);
+ }
+ }
}
- else
- oldScanKeys.remove(entry.getKey());
}
-
- if (!oldScanKeys.isEmpty())
+
+ // Look for deleted files
+ for (String file : oldScan.keySet())
{
-
- Iterator<String> keyItor = oldScanKeys.iterator();
- while (keyItor.hasNext())
+ if (!currentScan.containsKey(file))
{
- String filename = (String)keyItor.next();
- Log.debug("File removed: "+filename);
- reportRemoval(filename);
- bulkChanges.add(filename);
+ Notification old=_notifications.put(file,Notification.REMOVED);
+ if (old!=null)
+ {
+ switch(old)
+ {
+ case ADDED:
+ _notifications.remove(file);
+ }
+ }
}
}
+ if (Log.isDebugEnabled())
+ Log.debug("scanned "+_notifications);
+
+ // Process notifications
+ // Only process notifications that are for stable files (ie same in old and current scan).
+ List<String> bulkChanges = new ArrayList<String>();
+ for (Iterator<Entry<String,Notification>> iter = _notifications.entrySet().iterator();iter.hasNext();)
+ {
+ Entry<String,Notification> entry=iter.next();
+ String file=entry.getKey();
+
+ // Is the file stable?
+ if (oldScan.containsKey(file))
+ {
+ if (!oldScan.get(file).equals(currentScan.get(file)))
+ continue;
+ }
+ else if (currentScan.containsKey(file))
+ continue;
+
+ // File is stable so notify
+ Notification notification=entry.getValue();
+ iter.remove();
+ bulkChanges.add(file);
+ switch(notification)
+ {
+ case ADDED:
+ reportAddition(file);
+ break;
+ case CHANGED:
+ reportChange(file);
+ break;
+ case REMOVED:
+ reportRemoval(file);
+ break;
+ }
+ }
if (!bulkChanges.isEmpty())
reportBulkChanges(bulkChanges);
}
@@ -438,7 +528,7 @@ public class Scanner
* @param f file or directory
* @param scanInfoMap map of filenames to last modified times
*/
- private void scanFile (File f, Map<String,Long> scanInfoMap, int depth)
+ private void scanFile (File f, Map<String,TimeNSize> scanInfoMap, int depth)
{
try
{
@@ -450,8 +540,7 @@ public class Scanner
if ((_filter == null) || ((_filter != null) && _filter.accept(f.getParentFile(), f.getName())))
{
String name = f.getCanonicalPath();
- long lastModified = f.lastModified();
- scanInfoMap.put(name, new Long(lastModified));
+ scanInfoMap.put(name, new TimeNSize(f.lastModified(),f.length()));
}
}

Back to the top