diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java b/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java index fd082f51c0ba1ec63c5eb8949a402729c41e8c65..7eceddc3f671314062eeaafe9c06674676b64e8a 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java @@ -441,18 +441,21 @@ public final class FileUtilities { private boolean subDirectoriesOnly; - private final long stopWhenFindYounger; + private final long reference; + + private final boolean referenceIsRelative; private long lastChanged; private boolean terminated; - LastChangedWorker(File root, boolean subDirectoriesOnly, long stopWhenFindYounger) + LastChangedWorker(File root, boolean subDirectoriesOnly, long reference, boolean referenceIsRelative) { assert root != null; this.subDirectoriesOnly = subDirectoriesOnly; - this.stopWhenFindYounger = stopWhenFindYounger; + this.reference = reference; + this.referenceIsRelative = referenceIsRelative; this.terminated = false; this.lastChanged = 0; updateLastChanged(root); @@ -473,12 +476,23 @@ public final class FileUtilities } final long lastModified = path.lastModified(); lastChanged = Math.max(lastModified, lastChanged); - if (stopWhenFindYounger > 0 && lastChanged >= stopWhenFindYounger) + if (isYoungEnough(lastChanged)) { terminated = true; } } + private boolean isYoungEnough(long currentLastChanged) + { + if (referenceIsRelative) + { + return reference > 0 && currentLastChanged >= System.currentTimeMillis() - reference; + } else + { + return reference > 0 && currentLastChanged >= reference; + } + } + private void traverse(File path) { assert path != null; @@ -551,7 +565,32 @@ public final class FileUtilities */ public static long lastChanged(File path, boolean subDirectoriesOnly, long stopWhenFindYounger) { - return (new LastChangedWorker(path, subDirectoriesOnly, stopWhenFindYounger)).getLastChanged(); + return (new LastChangedWorker(path, subDirectoriesOnly, stopWhenFindYounger, false)).getLastChanged(); + } + + /** + * Determines the time (in milliseconds since start of the epoch) when any item below <var>path</var> has last been + * changed in the file system. + * + * @param path The path (file or directory) to check for last change. + * @param subDirectoriesOnly If <code>true</code>, only subdirectories of <var>path</var> are checked, if + * <var>path</var> is a directory. If <var>path</var> is a file, this parameter is ignored. When + * considering what this parameter is good for, note that the mtime of a directory is changed when an + * entry in the directory changes. + * @param stopWhenFindYoungerRelative If > 0, the recursive search for younger file will be stopped when a file + * or directory is found that is as young as or younger than + * <code>System.currentTimeMillis() - stopWhenYoungerRelative</code>. Supposed to be used when one + * does not care about the absolute youngest entry, but only, if there are entries that are "young + * enough". + * @return The time when any file in (or below) <var>path</var> has last been changed in the file system. + * @throws CheckedExceptionTunnel of an {@link IOException} if the <var>path</var> does not exist or is not + * readable. + * @throws CheckedExceptionTunnel of a {@link InterruptedException} if the thread that the method runs in gets + * interrupted. + */ + public static long lastChangedRelative(File path, boolean subDirectoriesOnly, long stopWhenFindYoungerRelative) + { + return (new LastChangedWorker(path, subDirectoriesOnly, stopWhenFindYoungerRelative, true)).getLastChanged(); } /** diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesLastChangedTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesLastChangedTest.java index c2e48c09325e2695d16ef9daab3e53c79bf2b3e3..4d11ece165f3463a0082b0250a49980518fb4d60 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesLastChangedTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesLastChangedTest.java @@ -127,5 +127,25 @@ public class FileUtilitiesLastChangedTest assertEquals(1000L, FileUtilities.lastChanged(dirA, false, 1000L)); assertEquals(1000L, FileUtilities.lastChanged(dirA, true, 1000L)); } + + @Test + public void testLastChangedRelative() throws IOException + { + final File dirA = new File(workingDirectory, "a-relative"); + final long now = System.currentTimeMillis(); + dirA.mkdir(); + dirA.deleteOnExit(); + final File fileB = new File(dirA, "b"); + fileB.createNewFile(); + fileB.deleteOnExit(); + final long fakedModTime1 = now - 10000L; + final long fakedModTime2 = now - 30000L; + fileB.setLastModified(fakedModTime1); + dirA.setLastModified(fakedModTime2); + final long diff1 = Math.abs(fakedModTime2 - FileUtilities.lastChangedRelative(dirA, false, 31000L)); + assertTrue("Difference to big: " + diff1 + " ms", diff1 < 1000L); + final long diff2 = Math.abs(fakedModTime1 - FileUtilities.lastChangedRelative(dirA, false, 11000L)); + assertTrue("Difference to big: " + diff2 + " ms", diff2 < 1000L); + } }