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 9613e7cf703164aefb7a5a1eb7236d2cad1486dd..a4fd2b8c61c35e661bb3886e60a49c931d06a3fc 100644 --- a/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java +++ b/common/source/java/ch/systemsx/cisd/common/utilities/FileUtilities.java @@ -25,9 +25,11 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Level; import org.apache.log4j.Logger; @@ -210,6 +212,7 @@ public final class FileUtilities /** * Checks whether a <var>path</var> of some <var>kind</var> is fully accessible to the program. * + * @param kindOfPath description of given <var>path</var>. Mainly used for error messages. * @return <code>null</code> if the <var>directory</var> is fully accessible and an error message describing the * problem with the <var>directory</var> otherwise. */ @@ -434,20 +437,115 @@ public final class FileUtilities }); } - /** Canonifies given relative path. */ - public final static String canonifyRelativePath(final String relativePath) + /** + * Removes given <var>prefix</var> from given <var>file</var> and returns a new <code>File</code>. + * <p> + * Returns given <var>file</var> if prefix is <i>empty</i> or could not be found in the file name. + * </p> + * + * @param file can not be <code>null</code>. + * @param prefix prefix that should be removed from the file name. Can be <code>null</code>. + */ + public final static File removePrefixFromFileName(File file, String prefix) { - if (relativePath == null) + assert file != null; + String name = file.getName(); + if (StringUtils.isEmpty(prefix)) { - return null; + return file; } - String canonifiedPath = FilenameUtils.separatorsToUnix(relativePath); - if (canonifiedPath.startsWith("/")) + if (name.indexOf(prefix) < 0) + { + return file; + } + return new File(file.getParent(), name.substring(prefix.length())); + } + + /** A <i>Java</i> pattern matching one or more digits. */ + private final static Pattern ONE_OR_MORE_DIGITS = Pattern.compile("(\\d+)"); + + public final static File createNextNumberedFile(File path, String defaultFileName) + { + return createNextNumberedFile(path, null, defaultFileName); + } + + /** + * Creates the next numbered file. + * <p> + * If the new suggested file already exists, then this method is called recursively. + * </p> + * + * @param defaultFileName the default name for the new file if the digit pattern could not be found (probably the + * starting file). + * @param regex pattern to find out the counter. If <code>null</code> then {@link #ONE_OR_MORE_DIGITS}} will be + * taken. The given <var>regex</var> must contain <code>(\\d+)</code>. + */ + public final static File createNextNumberedFile(File path, Pattern regex, String defaultFileName) + { + assert path != null; + final Pattern pattern; + if (regex == null) { - return canonifiedPath.substring(1); + pattern = ONE_OR_MORE_DIGITS; } else { - return canonifiedPath; + pattern = regex; + } + assert pattern.pattern().indexOf("(\\d+)") > -1; + + String pathName = path.getName(); + final Matcher matcher = pattern.matcher(pathName); + boolean found = matcher.find(); + if (found == false) + { + if (StringUtils.isEmpty(defaultFileName) == false) + { + return new File(path.getParent(), defaultFileName); + } + return path; + } + StringBuilder builder = new StringBuilder(); + int nextStart = 0; + while (found) + { + String group = matcher.group(1); + final int newNumber = Integer.parseInt(group) + 1; + builder.append(pathName.substring(nextStart, matcher.start(1))).append(newNumber); + nextStart = matcher.end(1); + found = matcher.find(); + } + builder.append(pathName.substring(nextStart)); + File newFile = new File(path.getParent(), builder.toString()); + if (newFile.exists()) + { + return createNextNumberedFile(newFile, pattern, defaultFileName); + } + return newFile; + } + + /** + * For given <var>root</var> and <var>file</var> extracts the relative <code>File</code>. + * <p> + * If given <var>file</var> does not contain given <var>root</var> path in its absolute path, then returns + * <code>null</code> (as the relative file could not be determined). + * </p> + */ + public final static File getRelativeFile(File root, File file) + { + assert file != null; + if (root == null) + { + return file; + } + String absolutePath = root.getAbsolutePath(); + final String strRoot = absolutePath + File.separator; + final String absoluteFile = file.getAbsolutePath(); + if (absoluteFile.startsWith(strRoot)) + { + return new File(absoluteFile.substring(strRoot.length())); + } else + { + return null; } } } diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesTest.java index 4288ea6f07d278fd3c3344e116bf9aff7bd73f63..a9cb1138c0ecbe8a68c3df85a432b23506fb67a0 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/FileUtilitiesTest.java @@ -16,17 +16,23 @@ package ch.systemsx.cisd.common.utilities; -import static org.testng.AssertJUnit.*; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.fail; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.regex.Pattern; +import org.apache.commons.io.FilenameUtils; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; +import ch.systemsx.cisd.common.Constants; import ch.systemsx.cisd.common.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.common.logging.LogInitializer; @@ -122,8 +128,7 @@ public class FileUtilitiesTest @Test public void testLoadToStringMissingResource() throws Exception { - final String thisFile = - FileUtilities.loadToString(getClass(), "/some/missing/resource"); + final String thisFile = FileUtilities.loadToString(getClass(), "/some/missing/resource"); assert thisFile == null; } @@ -144,12 +149,78 @@ public class FileUtilitiesTest assert file.delete(); assertEquals(Arrays.asList("Hello", "World!"), text); } - - public final void testCanonifyRelativePath() { - assertNull(FileUtilities.canonifyRelativePath(null)); - String relativePath = "/ch/systemsx/cisd/common/utilities/FileUtilitiesTest.class"; - assertEquals("ch/systemsx/cisd/common/utilities/FileUtilitiesTest.class", FileUtilities.canonifyRelativePath(relativePath)); - relativePath = "ch\\systemsx\\cisd\\common\\utilities\\FileUtilitiesTest.class"; - assertEquals("ch/systemsx/cisd/common/utilities/FileUtilitiesTest.class", FileUtilities.canonifyRelativePath(relativePath)); + + @Test + public final void testRemovePrefixFromFileName() + { + File file = new File("/tmp/dir/x.txt"); + try + { + FileUtilities.removePrefixFromFileName(null, Constants.IS_FINISHED_PREFIX); + fail("Given file can not be null."); + } catch (AssertionError e) + { + // Nothing to do here + } + assertEquals(file, FileUtilities.removePrefixFromFileName(file, null)); + assertEquals(file, FileUtilities.removePrefixFromFileName(file, Constants.IS_FINISHED_PREFIX)); + file = new File("/tmp/dir/" + Constants.IS_FINISHED_PREFIX + "x.txt"); + assertEquals("/tmp/dir/x.txt", FileUtilities.removePrefixFromFileName(file, Constants.IS_FINISHED_PREFIX) + .getPath()); + } + + @Test + public final void testCreateNextNumberedFile() + { + File file = new File(workingDirectory, "abc_[12]"); + assert file.exists() == false; + Pattern pattern = Pattern.compile("_\\[(\\d+)\\]"); + File newFile = FileUtilities.createNextNumberedFile(file, pattern, null); + assertEquals(FilenameUtils.getName(new File(workingDirectory, "abc_[13]").getPath()), FilenameUtils + .getName(newFile.getPath())); + file = new File(workingDirectory, "abc"); + newFile = FileUtilities.createNextNumberedFile(file, pattern, null); + assertEquals(FilenameUtils.getName(new File(workingDirectory, "abc").getPath()), FilenameUtils.getName(newFile + .getPath())); + try + { + FileUtilities.createNextNumberedFile(null, pattern, null); + fail("Null value for file not allowed."); + } catch (AssertionError e) + { + // Nothing to do here + } + newFile = FileUtilities.createNextNumberedFile(file, pattern, "abc_[1]"); + assertEquals(FilenameUtils.getName(new File(workingDirectory, "abc_[1]").getPath()), FilenameUtils + .getName(newFile.getPath())); + file = new File(workingDirectory, "a0bc1"); + newFile = FileUtilities.createNextNumberedFile(file, null); + assertEquals(FilenameUtils.getName(new File(workingDirectory, "a1bc2").getPath()), FilenameUtils + .getName(newFile.getPath())); + } + + @Test + public final void testGetRelativeFile() + { + try + { + FileUtilities.getRelativeFile(null, null); + fail("Given file can not be null."); + } catch (AssertionError e) + { + // Nothing to do here + } + File file = new File(workingDirectory, "hello"); + assertEquals(workingDirectory.getAbsolutePath() + File.separator + "hello", file.getAbsolutePath()); + assertEquals(file, FileUtilities.getRelativeFile(null, file)); + assertEquals(file, FileUtilities.getRelativeFile(new File(""), file)); + File root = new File("/temp"); + assertEquals("/temp", root.getAbsolutePath()); + File relativeFile = FileUtilities.getRelativeFile(root, file); + assertNull(relativeFile); + root = workingDirectory; + relativeFile = FileUtilities.getRelativeFile(root, file); + assertFalse(relativeFile.isAbsolute()); + assertEquals("hello", relativeFile.getPath()); } }