From 63a66d93a8c64d7bf783fdb0629a7b3874300ff7 Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 21 Jul 2016 14:11:42 -0400 Subject: [PATCH] added more PMD checks --- code-quality.gradle | 24 +++- .../repository/bagit/FileExistsVistor.java | 12 +- .../AddPayloadToBagManifestVistor.java | 16 +-- .../repository/bagit/creator/BagCreator.java | 32 ++--- .../gov/loc/repository/bagit/domain/Bag.java | 52 +++++--- .../repository/bagit/domain/FetchItem.java | 18 ++- .../repository/bagit/domain/KeyValuePair.java | 12 -- .../loc/repository/bagit/domain/Manifest.java | 9 +- .../loc/repository/bagit/domain/Version.java | 18 ++- .../exceptions/CorruptChecksumException.java | 2 +- .../FileNotInManifestException.java | 2 +- .../FileNotInPayloadDirectoryException.java | 2 +- .../InvalidBagMetadataException.java | 2 +- .../InvalidPayloadOxumException.java | 2 +- .../MaliciousManifestException.java | 2 +- .../exceptions/MissingBagitFileException.java | 2 +- .../MissingPayloadDirectoryException.java | 2 +- .../MissingPayloadManifestException.java | 2 +- .../PayloadOxumDoesNotExistException.java | 2 +- .../UnparsableVersionException.java | 2 +- .../UnsupportedAlgorithmException.java | 2 +- .../exceptions/VerificationException.java | 12 ++ ...orithmNameToSupportedAlgorithmMapping.java | 2 +- .../gov/loc/repository/bagit/hash/Hasher.java | 14 +- ...orithmNameToSupportedAlgorithmMapping.java | 6 +- .../hash/StandardSupportedAlgorithms.java | 2 +- .../bagit/hash/SupportedAlgorithm.java | 4 +- .../repository/bagit/reader/BagReader.java | 125 ++++++++++-------- .../bagit/tasks/CheckIfFileExistsTask.java | 9 +- .../bagit/tasks/CheckManifestHashsTask.java | 22 +-- .../loc/repository/bagit/util/PathUtils.java | 14 +- .../repository/bagit/verify/BagVerifier.java | 104 ++++++++------- .../verify/FileCountAndTotalSizeVistor.java | 14 +- .../PayloadFileExistsInManifestVistor.java | 10 +- .../repository/bagit/writer/BagWriter.java | 95 ++++++------- 35 files changed, 375 insertions(+), 275 deletions(-) delete mode 100644 src/main/java/gov/loc/repository/bagit/domain/KeyValuePair.java create mode 100644 src/main/java/gov/loc/repository/bagit/exceptions/VerificationException.java diff --git a/code-quality.gradle b/code-quality.gradle index ed7d2283d..0feec1f8b 100644 --- a/code-quality.gradle +++ b/code-quality.gradle @@ -34,16 +34,36 @@ jacocoTestReport.dependsOn test check.dependsOn integrationTest check.dependsOn jacocoTestReport +findbugsIntegrationTest.enabled = false findbugsTest.enabled = false findbugs { ignoreFailures = true //don't fail the gradle build if bugs are found } +pmdIntegrationTest.enabled = false pmdTest.enabled = false pmd { - ruleSets = ["java-basic", "java-braces", "java-empty"] + ruleSets = [ + "java-basic", + "java-braces", + "java-clone", + "java-codesize", + "java-design", + "java-empty", + "java-finalizers", + "java-imports", + "java-j2ee", + "java-javabeans", + "java-optimizations", + "java-strictexception", + "java-strings", + "java-sunsecure", + "java-typeresolution", + "java-unnecessary", + "java-unusedcode" + ] } jacocoTestReport { @@ -57,7 +77,7 @@ jacocoTestReport { 'gov.loc.repository.bagit/annotation/**', 'gov.loc.repository.bagit/exceptions/**']) }) -} + } } //Keep this for easy viewing of html findbugs report diff --git a/src/integration/java/gov/loc/repository/bagit/FileExistsVistor.java b/src/integration/java/gov/loc/repository/bagit/FileExistsVistor.java index ab169c04f..ee13e2d9d 100644 --- a/src/integration/java/gov/loc/repository/bagit/FileExistsVistor.java +++ b/src/integration/java/gov/loc/repository/bagit/FileExistsVistor.java @@ -10,16 +10,16 @@ import org.junit.Assert; public class FileExistsVistor extends SimpleFileVisitor{ - private final Path originalBag; - private final Path newBag; + private transient final Path originalBag; + private transient final Path newBag; - public FileExistsVistor(Path originalBag, Path newBag){ + public FileExistsVistor(final Path originalBag, final Path newBag){ this.originalBag = originalBag; this.newBag = newBag; } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { Path relative = originalBag.relativize(dir); Assert.assertTrue(Files.exists(newBag.resolve(relative))); @@ -27,8 +27,8 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)throws IOException{ - Path relative = originalBag.relativize(path); + public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs)throws IOException{ + final Path relative = originalBag.relativize(path); Assert.assertTrue(Files.exists(newBag.resolve(relative))); return FileVisitResult.CONTINUE; diff --git a/src/main/java/gov/loc/repository/bagit/creator/AddPayloadToBagManifestVistor.java b/src/main/java/gov/loc/repository/bagit/creator/AddPayloadToBagManifestVistor.java index a5b759a12..2d4b26596 100644 --- a/src/main/java/gov/loc/repository/bagit/creator/AddPayloadToBagManifestVistor.java +++ b/src/main/java/gov/loc/repository/bagit/creator/AddPayloadToBagManifestVistor.java @@ -23,18 +23,18 @@ public class AddPayloadToBagManifestVistor extends SimpleFileVisitor{ private static final Logger logger = LoggerFactory.getLogger(AddPayloadToBagManifestVistor.class); - private final Manifest manifest; - private final MessageDigest messageDigest; - private final boolean includeHiddenFiles; + private transient final Manifest manifest; + private transient final MessageDigest messageDigest; + private transient final boolean includeHiddenFiles; - public AddPayloadToBagManifestVistor(Manifest manifest, MessageDigest messageDigest, boolean includeHiddenFiles){ + public AddPayloadToBagManifestVistor(final Manifest manifest, final MessageDigest messageDigest, final boolean includeHiddenFiles){ this.manifest = manifest; this.messageDigest = messageDigest; this.includeHiddenFiles = includeHiddenFiles; } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if(!includeHiddenFiles && Files.isHidden(dir)){ logger.debug("Skipping [{}] since we are ignoring hidden files", dir); return FileVisitResult.SKIP_SUBTREE; @@ -49,13 +49,13 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)throws IOException{ + public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs)throws IOException{ if(!includeHiddenFiles && Files.isHidden(path) && !path.endsWith(".keep")){ logger.debug("Skipping [{}] since we are ignoring hidden files", path); } else{ - InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ); - String hash = Hasher.hash(inputStream, messageDigest); + final InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ); + final String hash = Hasher.hash(inputStream, messageDigest); logger.debug("Adding [{}] to manifest with hash [{}]", path, hash); manifest.getFileToChecksumMap().put(path, hash); } diff --git a/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java b/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java index 4de6f9d04..4f50ae314 100644 --- a/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java +++ b/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java @@ -21,9 +21,11 @@ /** * Responsible for creating a bag in place. */ -public class BagCreator { +public final class BagCreator { private static final Logger logger = LoggerFactory.getLogger(BagVerifier.class); + private BagCreator(){} + /** * Creates a basic(only required elements) bag in place for version 0.97. * This method moves and creates files, thus if an error is thrown during operation it may leave the filesystem @@ -36,24 +38,24 @@ public class BagCreator { * @throws IOException if there is a problem writing or moving file(s) * @return a {@link Bag} object representing the newly created bagit bag */ - public static Bag bagInPlace(Path root, SupportedAlgorithm algorithm, boolean includeHidden) throws NoSuchAlgorithmException, IOException{ - Bag bag = new Bag(new Version(0, 97)); + public static Bag bagInPlace(final Path root, final SupportedAlgorithm algorithm, final boolean includeHidden) throws NoSuchAlgorithmException, IOException{ + final Bag bag = new Bag(new Version(0, 97)); bag.setRootDir(root); logger.info("Creating a bag with version: [{}] in directory: [{}]", bag.getVersion(), root); - Path dataDir = root.resolve("data"); + final Path dataDir = root.resolve("data"); Files.createDirectory(dataDir); - DirectoryStream directoryStream = Files.newDirectoryStream(root); - for(Path path : directoryStream){ + final DirectoryStream directoryStream = Files.newDirectoryStream(root); + for(final Path path : directoryStream){ if(!path.equals(dataDir) && !Files.isHidden(path) || includeHidden){ Files.move(path, dataDir.resolve(path.getFileName())); } } logger.info("Creating payload manifest"); - Manifest manifest = new Manifest(algorithm); - MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getMessageDigestName()); - AddPayloadToBagManifestVistor visitor = new AddPayloadToBagManifestVistor(manifest, messageDigest, includeHidden); + final Manifest manifest = new Manifest(algorithm); + final MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getMessageDigestName()); + final AddPayloadToBagManifestVistor visitor = new AddPayloadToBagManifestVistor(manifest, messageDigest, includeHidden); Files.walkFileTree(dataDir, visitor); bag.getPayLoadManifests().add(manifest); @@ -77,18 +79,18 @@ public static Bag bagInPlace(Path root, SupportedAlgorithm algorithm, boolean in * @throws IOException if there is a problem writing files or .bagit directory */ @Incubating - public static Bag createDotBagit(Path root, SupportedAlgorithm algorithm, boolean includeHidden) throws NoSuchAlgorithmException, IOException{ - Bag bag = new Bag(new Version(0, 98)); + public static Bag createDotBagit(final Path root, final SupportedAlgorithm algorithm, final boolean includeHidden) throws NoSuchAlgorithmException, IOException{ + final Bag bag = new Bag(new Version(0, 98)); bag.setRootDir(root); logger.info("Creating a bag with version: [{}] in directory: [{}]", bag.getVersion(), root); - Path dotbagitDir = root.resolve(".bagit"); + final Path dotbagitDir = root.resolve(".bagit"); Files.createDirectories(dotbagitDir); logger.info("Creating payload manifest"); - Manifest manifest = new Manifest(algorithm); - MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getMessageDigestName()); - AddPayloadToBagManifestVistor visitor = new AddPayloadToBagManifestVistor(manifest, messageDigest, includeHidden); + final Manifest manifest = new Manifest(algorithm); + final MessageDigest messageDigest = MessageDigest.getInstance(algorithm.getMessageDigestName()); + final AddPayloadToBagManifestVistor visitor = new AddPayloadToBagManifestVistor(manifest, messageDigest, includeHidden); Files.walkFileTree(root, visitor); bag.getPayLoadManifests().add(manifest); diff --git a/src/main/java/gov/loc/repository/bagit/domain/Bag.java b/src/main/java/gov/loc/repository/bagit/domain/Bag.java index 044b5f984..69745844f 100644 --- a/src/main/java/gov/loc/repository/bagit/domain/Bag.java +++ b/src/main/java/gov/loc/repository/bagit/domain/Bag.java @@ -36,14 +36,28 @@ public class Bag { //the current location of the bag on the filesystem private Path rootDir; + /** + * empty bag with an invalid version + */ public Bag(){ + //intentionally empty } - public Bag(Version version){ + /** + * empty bag with the specified bag version + * + * @param version the version of the bag + */ + public Bag(final Version version){ this.version = version; } - public Bag(Bag bag){ + /** + * Create a new bag with the same values as the supplied bag + * + * @param bag the bag to clone + */ + public Bag(final Bag bag){ this.version = bag.getVersion(); this.fileEncoding = bag.fileEncoding; this.itemsToFetch = bag.getItemsToFetch(); @@ -61,7 +75,7 @@ public Set getPayLoadManifests() { return payLoadManifests; } - public void setPayLoadManifests(Set payLoadManifests) { + public void setPayLoadManifests(final Set payLoadManifests) { this.payLoadManifests = payLoadManifests; } @@ -69,7 +83,7 @@ public Set getTagManifests() { return tagManifests; } - public void setTagManifests(Set tagManifests) { + public void setTagManifests(final Set tagManifests) { this.tagManifests = tagManifests; } @@ -77,7 +91,7 @@ public List getItemsToFetch() { return itemsToFetch; } - public void setItemsToFetch(List itemsToFetch) { + public void setItemsToFetch(final List itemsToFetch) { this.itemsToFetch = itemsToFetch; } @@ -85,7 +99,7 @@ public List> getMetadata() { return metadata; } - public void setMetadata(List> metadata) { + public void setMetadata(final List> metadata) { this.metadata = metadata; } @@ -93,25 +107,25 @@ public Charset getFileEncoding() { return fileEncoding; } - public void setFileEncoding(Charset fileEncoding) { + public void setFileEncoding(final Charset fileEncoding) { this.fileEncoding = fileEncoding; } @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Bag [version=").append(version); - sb.append(", fileEncoding=").append(fileEncoding); - sb.append(", payLoadManifests=["); - for(Manifest payloadManifest : payLoadManifests){ + final StringBuilder sb = new StringBuilder(95); + sb.append("Bag [version=").append(version). + append(", fileEncoding=").append(fileEncoding). + append(", payLoadManifests=["); + for(final Manifest payloadManifest : payLoadManifests){ sb.append(payloadManifest).append(' '); } sb.append("], tagManifests=["); - for(Manifest tagManifest : tagManifests){ + for(final Manifest tagManifest : tagManifests){ sb.append(tagManifest).append(' '); } - sb.append("], itemsToFetch=").append(itemsToFetch); - sb.append(", metadata=").append(metadata).append(']'); + sb.append("], itemsToFetch=").append(itemsToFetch). + append(", metadata=").append(metadata).append(']'); return sb.toString(); } @@ -123,7 +137,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj){ return true; } @@ -134,7 +148,7 @@ public boolean equals(Object obj) { return false; } - Bag other = (Bag) obj; + final Bag other = (Bag) obj; return Objects.equals(this.version, other.getVersion()) && Objects.equals(this.fileEncoding, other.getFileEncoding()) && Objects.equals(this.payLoadManifests, other.getPayLoadManifests()) && @@ -147,11 +161,11 @@ public Path getRootDir() { return rootDir; } - public void setRootDir(Path rootDir) { + public void setRootDir(final Path rootDir) { this.rootDir = rootDir; } - public void setVersion(Version version) { + public void setVersion(final Version version) { this.version = version; } } diff --git a/src/main/java/gov/loc/repository/bagit/domain/FetchItem.java b/src/main/java/gov/loc/repository/bagit/domain/FetchItem.java index 4af8cc21f..c5b72e085 100644 --- a/src/main/java/gov/loc/repository/bagit/domain/FetchItem.java +++ b/src/main/java/gov/loc/repository/bagit/domain/FetchItem.java @@ -22,7 +22,7 @@ public class FetchItem { */ public final String path; - public FetchItem(URL url, Long length, String path){ + public FetchItem(final URL url, final Long length, final String path){ this.url = url; this.length = length; this.path = path; @@ -30,11 +30,11 @@ public FetchItem(URL url, Long length, String path){ @Override public String toString() { - StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(); sb.append(url).append(' '); if(length < 0){ - sb.append('-').append(' '); + sb.append("- "); } else{ sb.append(length).append(' '); @@ -44,4 +44,16 @@ public String toString() { return sb.toString(); } + + public URL getUrl() { + return url; + } + + public Long getLength() { + return length; + } + + public String getPath() { + return path; + } } diff --git a/src/main/java/gov/loc/repository/bagit/domain/KeyValuePair.java b/src/main/java/gov/loc/repository/bagit/domain/KeyValuePair.java deleted file mode 100644 index 898cfd817..000000000 --- a/src/main/java/gov/loc/repository/bagit/domain/KeyValuePair.java +++ /dev/null @@ -1,12 +0,0 @@ -package gov.loc.repository.bagit.domain; - -import javafx.util.Pair; - -public class KeyValuePair extends Pair { - private static final long serialVersionUID = 1L; - - public KeyValuePair(String key, String value) { - super(key, value); - } - -} diff --git a/src/main/java/gov/loc/repository/bagit/domain/Manifest.java b/src/main/java/gov/loc/repository/bagit/domain/Manifest.java index 2cb7ef0d3..5d0c4299a 100644 --- a/src/main/java/gov/loc/repository/bagit/domain/Manifest.java +++ b/src/main/java/gov/loc/repository/bagit/domain/Manifest.java @@ -3,6 +3,7 @@ import java.nio.file.Path; import java.util.HashMap; +import java.util.Map; import gov.loc.repository.bagit.hash.SupportedAlgorithm; @@ -11,17 +12,17 @@ */ public class Manifest { private final SupportedAlgorithm algorithm; - private HashMap fileToChecksumMap = new HashMap<>(); + private Map fileToChecksumMap = new HashMap<>(); - public Manifest(SupportedAlgorithm algorithm){ + public Manifest(final SupportedAlgorithm algorithm){ this.algorithm = algorithm; } - public HashMap getFileToChecksumMap() { + public Map getFileToChecksumMap() { return fileToChecksumMap; } - public void setFileToChecksumMap(HashMap fileToChecksumMap) { + public void setFileToChecksumMap(final Map fileToChecksumMap) { this.fileToChecksumMap = fileToChecksumMap; } diff --git a/src/main/java/gov/loc/repository/bagit/domain/Version.java b/src/main/java/gov/loc/repository/bagit/domain/Version.java index f13e5605a..557c49cfa 100644 --- a/src/main/java/gov/loc/repository/bagit/domain/Version.java +++ b/src/main/java/gov/loc/repository/bagit/domain/Version.java @@ -6,9 +6,9 @@ public class Version implements Comparable{ public final int major; public final int minor; - private final String cachedToString; + private transient final String cachedToString; - public Version(int major, int minor){ + public Version(final int major, final int minor){ this.major = major; this.minor = minor; this.cachedToString = major + "." + minor; @@ -20,7 +20,7 @@ public String toString() { } @Override - public int compareTo(Version o) { + public int compareTo(final Version o) { //a negative integer - this is less than specified object //zero - equal to specified object //positive - greater than the specified object @@ -40,7 +40,7 @@ public int hashCode() { } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj){ return true; } @@ -51,8 +51,16 @@ public boolean equals(Object obj) { return false; } - Version other = (Version) obj; + final Version other = (Version) obj; return Objects.equals(major, other.major) && Objects.equals(minor, other.minor); } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/CorruptChecksumException.java b/src/main/java/gov/loc/repository/bagit/exceptions/CorruptChecksumException.java index f8f286e33..637ff0e48 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/CorruptChecksumException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/CorruptChecksumException.java @@ -6,7 +6,7 @@ public class CorruptChecksumException extends Exception { private static final long serialVersionUID = 1L; - public CorruptChecksumException(String message){ + public CorruptChecksumException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInManifestException.java b/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInManifestException.java index d34e31a91..7447a220c 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInManifestException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInManifestException.java @@ -9,7 +9,7 @@ public class FileNotInManifestException extends IOException { private static final long serialVersionUID = 1L; - public FileNotInManifestException(String message){ + public FileNotInManifestException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInPayloadDirectoryException.java b/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInPayloadDirectoryException.java index 19f9b9ac0..870f9a658 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInPayloadDirectoryException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/FileNotInPayloadDirectoryException.java @@ -7,7 +7,7 @@ public class FileNotInPayloadDirectoryException extends Exception { private static final long serialVersionUID = 1L; - public FileNotInPayloadDirectoryException(String message){ + public FileNotInPayloadDirectoryException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/InvalidBagMetadataException.java b/src/main/java/gov/loc/repository/bagit/exceptions/InvalidBagMetadataException.java index 8d80d060f..0fc2ed340 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/InvalidBagMetadataException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/InvalidBagMetadataException.java @@ -11,7 +11,7 @@ public class InvalidBagMetadataException extends Exception { private static final long serialVersionUID = 1L; - public InvalidBagMetadataException(String message){ + public InvalidBagMetadataException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/InvalidPayloadOxumException.java b/src/main/java/gov/loc/repository/bagit/exceptions/InvalidPayloadOxumException.java index 87f52f13a..7c0c4d2d0 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/InvalidPayloadOxumException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/InvalidPayloadOxumException.java @@ -7,7 +7,7 @@ public class InvalidPayloadOxumException extends Exception { private static final long serialVersionUID = 1L; - public InvalidPayloadOxumException(String message){ + public InvalidPayloadOxumException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/MaliciousManifestException.java b/src/main/java/gov/loc/repository/bagit/exceptions/MaliciousManifestException.java index 5774d368d..a777dcb4a 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/MaliciousManifestException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/MaliciousManifestException.java @@ -7,7 +7,7 @@ public class MaliciousManifestException extends Exception { private static final long serialVersionUID = 1L; - public MaliciousManifestException(String message){ + public MaliciousManifestException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/MissingBagitFileException.java b/src/main/java/gov/loc/repository/bagit/exceptions/MissingBagitFileException.java index 580dcba39..c7c45c7d0 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/MissingBagitFileException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/MissingBagitFileException.java @@ -6,7 +6,7 @@ public class MissingBagitFileException extends Exception { private static final long serialVersionUID = 1L; - public MissingBagitFileException(String message){ + public MissingBagitFileException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadDirectoryException.java b/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadDirectoryException.java index 0817736cc..766b05aa7 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadDirectoryException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadDirectoryException.java @@ -6,7 +6,7 @@ public class MissingPayloadDirectoryException extends Exception { private static final long serialVersionUID = 1L; - public MissingPayloadDirectoryException(String message){ + public MissingPayloadDirectoryException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadManifestException.java b/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadManifestException.java index 0689d2671..7cc9b9d6a 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadManifestException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/MissingPayloadManifestException.java @@ -6,7 +6,7 @@ public class MissingPayloadManifestException extends Exception { private static final long serialVersionUID = 1L; - public MissingPayloadManifestException(String message){ + public MissingPayloadManifestException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/PayloadOxumDoesNotExistException.java b/src/main/java/gov/loc/repository/bagit/exceptions/PayloadOxumDoesNotExistException.java index 34f715cd2..e35c28e70 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/PayloadOxumDoesNotExistException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/PayloadOxumDoesNotExistException.java @@ -9,7 +9,7 @@ public class PayloadOxumDoesNotExistException extends RuntimeException { private static final long serialVersionUID = 1L; - public PayloadOxumDoesNotExistException(String message){ + public PayloadOxumDoesNotExistException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/UnparsableVersionException.java b/src/main/java/gov/loc/repository/bagit/exceptions/UnparsableVersionException.java index bd12ae1fb..c0eeb1426 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/UnparsableVersionException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/UnparsableVersionException.java @@ -6,7 +6,7 @@ public class UnparsableVersionException extends Exception { private static final long serialVersionUID = 1L; - public UnparsableVersionException(String message){ + public UnparsableVersionException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/UnsupportedAlgorithmException.java b/src/main/java/gov/loc/repository/bagit/exceptions/UnsupportedAlgorithmException.java index 7b07e3d9b..e7a7d684c 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/UnsupportedAlgorithmException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/UnsupportedAlgorithmException.java @@ -6,7 +6,7 @@ public class UnsupportedAlgorithmException extends Exception { private static final long serialVersionUID = 1L; - public UnsupportedAlgorithmException(String message){ + public UnsupportedAlgorithmException(final String message){ super(message); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/VerificationException.java b/src/main/java/gov/loc/repository/bagit/exceptions/VerificationException.java new file mode 100644 index 000000000..c0be429a8 --- /dev/null +++ b/src/main/java/gov/loc/repository/bagit/exceptions/VerificationException.java @@ -0,0 +1,12 @@ +package gov.loc.repository.bagit.exceptions; + +/** + * Class to represent an generic exception that happened during verification + */ +public class VerificationException extends Exception { + private static final long serialVersionUID = 1L; + + public VerificationException(final Exception exception){ + super(exception); + } +} diff --git a/src/main/java/gov/loc/repository/bagit/hash/BagitAlgorithmNameToSupportedAlgorithmMapping.java b/src/main/java/gov/loc/repository/bagit/hash/BagitAlgorithmNameToSupportedAlgorithmMapping.java index 4ee2a1d7c..fd84b74d7 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/BagitAlgorithmNameToSupportedAlgorithmMapping.java +++ b/src/main/java/gov/loc/repository/bagit/hash/BagitAlgorithmNameToSupportedAlgorithmMapping.java @@ -4,5 +4,5 @@ * Implement this interface if you need to be able to use other algorithms than the {@link StandardSupportedAlgorithms} */ public interface BagitAlgorithmNameToSupportedAlgorithmMapping { - public SupportedAlgorithm getMessageDigestName(String bagitAlgorithmName); + SupportedAlgorithm getMessageDigestName(String bagitAlgorithmName); } diff --git a/src/main/java/gov/loc/repository/bagit/hash/Hasher.java b/src/main/java/gov/loc/repository/bagit/hash/Hasher.java index 46882839f..1f18b76aa 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/Hasher.java +++ b/src/main/java/gov/loc/repository/bagit/hash/Hasher.java @@ -9,7 +9,11 @@ /** * Convenience class for generating a HEX formatted string of the checksum hash. */ -public class Hasher { +public final class Hasher { + + private Hasher(){ + //intentionall left empty + } /** * Create a HEX formatted string of the checksum hash @@ -20,7 +24,7 @@ public class Hasher { * @throws IOException if there is a problem reading the file */ public static String hash(final InputStream inputStream, final MessageDigest messageDigest) throws IOException { - InputStream is = new BufferedInputStream(inputStream); + final InputStream is = new BufferedInputStream(inputStream); final byte[] buffer = new byte[1024]; int read = is.read(buffer); @@ -34,14 +38,14 @@ public static String hash(final InputStream inputStream, final MessageDigest mes } //Convert the byte to hex format - protected static String formatMessageDigest(final MessageDigest messageDigest){ - Formatter formatter = new Formatter(); + private static String formatMessageDigest(final MessageDigest messageDigest){ + final Formatter formatter = new Formatter(); for (final byte b : messageDigest.digest()) { formatter.format("%02x", b); } - String hash = formatter.toString(); + final String hash = formatter.toString(); formatter.close(); return hash; diff --git a/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java b/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java index 1c4421781..9775f27a7 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java +++ b/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java @@ -1,5 +1,7 @@ package gov.loc.repository.bagit.hash; +import java.util.Locale; + /** * Provides a mapping between bagit algorithm names and {@link SupportedAlgorithm} */ @@ -7,7 +9,7 @@ public class StandardBagitAlgorithmNameToSupportedAlgorithmMapping implements BagitAlgorithmNameToSupportedAlgorithmMapping { @Override - public SupportedAlgorithm getMessageDigestName(String bagitAlgorithmName) { - return StandardSupportedAlgorithms.valueOf(bagitAlgorithmName.toUpperCase()); + public SupportedAlgorithm getMessageDigestName(final String bagitAlgorithmName) { + return StandardSupportedAlgorithms.valueOf(bagitAlgorithmName.toUpperCase(Locale.getDefault())); } } diff --git a/src/main/java/gov/loc/repository/bagit/hash/StandardSupportedAlgorithms.java b/src/main/java/gov/loc/repository/bagit/hash/StandardSupportedAlgorithms.java index 9b700583f..edef8430f 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/StandardSupportedAlgorithms.java +++ b/src/main/java/gov/loc/repository/bagit/hash/StandardSupportedAlgorithms.java @@ -11,7 +11,7 @@ public enum StandardSupportedAlgorithms implements SupportedAlgorithm{ private final String messageDigestName; - private StandardSupportedAlgorithms(String messageDigestName){ + private StandardSupportedAlgorithms(final String messageDigestName){ this.messageDigestName = messageDigestName; } diff --git a/src/main/java/gov/loc/repository/bagit/hash/SupportedAlgorithm.java b/src/main/java/gov/loc/repository/bagit/hash/SupportedAlgorithm.java index a89696fce..d5558ca63 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/SupportedAlgorithm.java +++ b/src/main/java/gov/loc/repository/bagit/hash/SupportedAlgorithm.java @@ -7,6 +7,6 @@ * See {@link StandardSupportedAlgorithms} for a list of defaults */ public interface SupportedAlgorithm { - public String getMessageDigestName(); - public String getBagitName(); + String getMessageDigestName(); + String getBagitName(); } diff --git a/src/main/java/gov/loc/repository/bagit/reader/BagReader.java b/src/main/java/gov/loc/repository/bagit/reader/BagReader.java index 75465a39b..bc65731fe 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/BagReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/BagReader.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +33,7 @@ /** * Responsible for reading a bag from the filesystem. */ +@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public class BagReader { private static final Logger logger = LoggerFactory.getLogger(PayloadFileExistsInManifestVistor.class); @@ -41,7 +43,7 @@ public BagReader(){ this.nameMapping = new StandardBagitAlgorithmNameToSupportedAlgorithmMapping(); } - public BagReader(BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ + public BagReader(final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ this.nameMapping = nameMapping; } @@ -56,14 +58,14 @@ public BagReader(BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ * @throws MaliciousManifestException if there is path that is referenced in the manifest that is outside the bag root directory * @throws InvalidBagMetadataException if the metadata or bagit.txt file does not conform to the bagit spec */ - public Bag read(Path rootDir) throws IOException, UnparsableVersionException, MaliciousManifestException, InvalidBagMetadataException{ + public Bag read(final Path rootDir) throws IOException, UnparsableVersionException, MaliciousManifestException, InvalidBagMetadataException{ //@Incubating Path bagitDir = rootDir.resolve(".bagit"); if(!Files.exists(bagitDir)){ bagitDir = rootDir; } - Path bagitFile = bagitDir.resolve("bagit.txt"); + final Path bagitFile = bagitDir.resolve("bagit.txt"); Bag bag = readBagitTextFile(bagitFile, new Bag()); bag.setRootDir(rootDir); @@ -71,7 +73,7 @@ public Bag read(Path rootDir) throws IOException, UnparsableVersionException, Ma bag = readBagMetadata(bagitDir, bag); - Path fetchFile = bagitDir.resolve("fetch.txt"); + final Path fetchFile = bagitDir.resolve("fetch.txt"); if(Files.exists(fetchFile)){ bag = readFetch(fetchFile, bag); } @@ -91,13 +93,13 @@ public Bag read(Path rootDir) throws IOException, UnparsableVersionException, Ma * @throws UnparsableVersionException if there is a problem parsing the bagit version number * @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec */ - public Bag readBagitTextFile(Path bagitFile, Bag bag) throws IOException, UnparsableVersionException, InvalidBagMetadataException{ + public Bag readBagitTextFile(final Path bagitFile, final Bag bag) throws IOException, UnparsableVersionException, InvalidBagMetadataException{ logger.debug("Reading bagit.txt file"); - List> pairs = readKeyValuesFromFile(bagitFile, ":"); + final List> pairs = readKeyValuesFromFile(bagitFile, ":"); String version = ""; Charset encoding = StandardCharsets.UTF_8; - for(Pair pair : pairs){ + for(final Pair pair : pairs){ if("BagIt-Version".equals(pair.getKey())){ version = pair.getValue(); logger.debug("BagIt-Version is [{}]", version); @@ -108,21 +110,21 @@ public Bag readBagitTextFile(Path bagitFile, Bag bag) throws IOException, Unpars } } - Bag newBag = new Bag(bag); + final Bag newBag = new Bag(bag); newBag.setVersion(parseVersion(version)); newBag.setFileEncoding(encoding); return newBag; } - protected Version parseVersion(String version) throws UnparsableVersionException{ + protected Version parseVersion(final String version) throws UnparsableVersionException{ if(!version.contains(".")){ throw new UnparsableVersionException("Version must be in format MAJOR.MINOR but was " + version); } - String[] parts = version.split("\\."); - int major = Integer.parseInt(parts[0]); - int minor = Integer.parseInt(parts[1]); + final String[] parts = version.split("\\."); + final int major = Integer.parseInt(parts[0]); + final int minor = Integer.parseInt(parts[1]); return new Version(major, minor); } @@ -138,13 +140,13 @@ protected Version parseVersion(String version) throws UnparsableVersionException * @throws IOException if there is a problem reading a file * @throws MaliciousManifestException if there is path that is referenced in the manifest that is outside the bag root directory */ - public Bag readAllManifests(Path rootDir, Bag bag) throws IOException, MaliciousManifestException{ + public Bag readAllManifests(final Path rootDir, final Bag bag) throws IOException, MaliciousManifestException{ logger.info("Attempting to find and read manifests"); - Bag newBag = new Bag(bag); - DirectoryStream manifests = getAllManifestFiles(rootDir); + final Bag newBag = new Bag(bag); + final DirectoryStream manifests = getAllManifestFiles(rootDir); - for (Path path : manifests){ - String filename = PathUtils.getFilename(path); + for (final Path path : manifests){ + final String filename = PathUtils.getFilename(path); if(filename.startsWith("tagmanifest-")){ logger.debug("Found tag manifest [{}]", path); @@ -159,11 +161,11 @@ else if(filename.startsWith("manifest-")){ return newBag; } - protected DirectoryStream getAllManifestFiles(Path rootDir) throws IOException{ - DirectoryStream.Filter filter = new DirectoryStream.Filter() { - public boolean accept(Path file) throws IOException { + protected DirectoryStream getAllManifestFiles(final Path rootDir) throws IOException{ + final DirectoryStream.Filter filter = new DirectoryStream.Filter() { + public boolean accept(final Path file) throws IOException { if(file == null || file.getFileName() == null){ return false;} - String filename = PathUtils.getFilename(file); + final String filename = PathUtils.getFilename(file); return filename.startsWith("tagmanifest-") || filename.startsWith("manifest-"); } }; @@ -181,27 +183,27 @@ public boolean accept(Path file) throws IOException { * @throws IOException if there is a problem reading a file * @throws MaliciousManifestException if there is path that is referenced in the manifest that is outside the bag root directory */ - public Manifest readManifest(Path manifestFile, Path bagRootDir) throws IOException, MaliciousManifestException{ + public Manifest readManifest(final Path manifestFile, final Path bagRootDir) throws IOException, MaliciousManifestException{ logger.debug("Reading manifest [{}]", manifestFile); - String alg = PathUtils.getFilename(manifestFile).split("[-\\.]")[1]; - SupportedAlgorithm algorithm = nameMapping.getMessageDigestName(alg); + final String alg = PathUtils.getFilename(manifestFile).split("[-\\.]")[1]; + final SupportedAlgorithm algorithm = nameMapping.getMessageDigestName(alg); - Manifest manifest = new Manifest(algorithm); + final Manifest manifest = new Manifest(algorithm); - HashMap filetToChecksumMap = readChecksumFileMap(manifestFile, bagRootDir); + final Map filetToChecksumMap = readChecksumFileMap(manifestFile, bagRootDir); manifest.setFileToChecksumMap(filetToChecksumMap); return manifest; } - protected HashMap readChecksumFileMap(Path manifestFile, Path bagRootDir) throws IOException, MaliciousManifestException{ - HashMap map = new HashMap<>(); - BufferedReader br = Files.newBufferedReader(manifestFile); + protected Map readChecksumFileMap(final Path manifestFile, final Path bagRootDir) throws IOException, MaliciousManifestException{ + final HashMap map = new HashMap<>(); + final BufferedReader br = Files.newBufferedReader(manifestFile); String line = br.readLine(); while(line != null){ - String[] parts = line.split("\\s+", 2); - Path file = bagRootDir.resolve(PathUtils.decodeFilname(parts[1])); + final String[] parts = line.split("\\s+", 2); + final Path file = bagRootDir.resolve(PathUtils.decodeFilname(parts[1])); if(!file.normalize().startsWith(bagRootDir)){ throw new MaliciousManifestException("Path " + file + " is outside the bag root directory of " + bagRootDir + "! This is not allowed according to the bagit specification!"); @@ -225,18 +227,18 @@ protected HashMap readChecksumFileMap(Path manifestFile, Path bagR * @throws IOException if there is a problem reading a file * @throws InvalidBagMetadataException if the metadata file does not conform to the bagit spec */ - public Bag readBagMetadata(Path rootDir, Bag bag) throws IOException, InvalidBagMetadataException{ + public Bag readBagMetadata(final Path rootDir, final Bag bag) throws IOException, InvalidBagMetadataException{ //TODO update for .bagit being yaml... logger.info("Attempting to read bag metadata file"); - Bag newBag = new Bag(bag); + final Bag newBag = new Bag(bag); List> metadata = new ArrayList<>(); - Path bagInfoFile = rootDir.resolve("bag-info.txt"); + final Path bagInfoFile = rootDir.resolve("bag-info.txt"); if(Files.exists(bagInfoFile)){ logger.debug("Found [{}] file", bagInfoFile); metadata = readKeyValuesFromFile(bagInfoFile, ":"); } - Path packageInfoFile = rootDir.resolve("package-info.txt"); //only exists in versions 0.93 - 0.95 + final Path packageInfoFile = rootDir.resolve("package-info.txt"); //only exists in versions 0.93 - 0.95 if(Files.exists(packageInfoFile)){ logger.debug("Found [{}] file", packageInfoFile); metadata = readKeyValuesFromFile(packageInfoFile, ":"); @@ -257,19 +259,22 @@ public Bag readBagMetadata(Path rootDir, Bag bag) throws IOException, InvalidBag * * @throws IOException if there is a problem reading a file */ - public Bag readFetch(Path fetchFile, Bag bag) throws IOException{ + public Bag readFetch(final Path fetchFile, final Bag bag) throws IOException{ logger.info("Attempting to read [{}]", fetchFile); - Bag newBag = new Bag(bag); - BufferedReader br = Files.newBufferedReader(fetchFile); + final Bag newBag = new Bag(bag); + final BufferedReader br = Files.newBufferedReader(fetchFile); String line = br.readLine(); + String[] parts = null; + long length = 0; + URL url = null; while(line != null){ - String[] parts = line.split("\\s+", 3); - long length = parts[1].equals("-") ? -1 : Long.decode(parts[1]); - URL url = new URL(parts[0]); + parts = line.split("\\s+", 3); + length = parts[1].equals("-") ? -1 : Long.decode(parts[1]); + url = new URL(parts[0]); logger.debug("Read URL [{}] length [{}] path [{}] from fetch file [{}]", url, length, parts[2], fetchFile); - FetchItem itemToFetch = new FetchItem(url, length, parts[2]); + final FetchItem itemToFetch = new FetchItem(url, length, parts[2]); newBag.getItemsToFetch().add(itemToFetch); line = br.readLine(); @@ -278,33 +283,33 @@ public Bag readFetch(Path fetchFile, Bag bag) throws IOException{ return newBag; } - protected List> readKeyValuesFromFile(Path file, String splitRegex) throws IOException, InvalidBagMetadataException{ - List> keyValues = new ArrayList<>(); - BufferedReader br = Files.newBufferedReader(file); + protected List> readKeyValuesFromFile(final Path file, final String splitRegex) throws IOException, InvalidBagMetadataException{ + final List> keyValues = new ArrayList<>(); + final BufferedReader br = Files.newBufferedReader(file); String line = br.readLine(); while(line != null){ if(line.matches("^\\s+.*")){ - Pair oldKeyValue = keyValues.remove(keyValues.size() -1); - Pair newKeyValue = new Pair(oldKeyValue.getKey(), oldKeyValue.getValue() + System.lineSeparator() +line); + final Pair oldKeyValue = keyValues.remove(keyValues.size() -1); + final Pair newKeyValue = new Pair(oldKeyValue.getKey(), oldKeyValue.getValue() + System.lineSeparator() +line); keyValues.add(newKeyValue); logger.debug("Found an indented line - merging it with key [{}]", oldKeyValue.getKey()); } else{ - String[] parts = line.split(splitRegex, 2); + final String[] parts = line.split(splitRegex, 2); if(parts.length != 2){ - StringBuilder message = new StringBuilder(); - message.append("Line ").append('[').append(line) - .append("] does not meet the bagit specification for a bag tag file. Perhaps you meant to indent it ") - .append("by a space or a tab? Or perhaps you didn't use a colon to separate the key from the value?") - .append("It must follow the form of : or if continuing from another line must be indented ") - .append("by a space or a tab."); + final StringBuilder message = new StringBuilder(300); + message.append("Line [").append(line) + .append("] does not meet the bagit specification for a bag tag file. Perhaps you meant to indent it " + + "by a space or a tab? Or perhaps you didn't use a colon to separate the key from the value?" + + "It must follow the form of : or if continuing from another line must be indented " + + "by a space or a tab."); throw new InvalidBagMetadataException(message.toString()); } - String key = parts[0].trim(); - String value = parts[1].trim(); + final String key = parts[0].trim(); + final String value = parts[1].trim(); logger.debug("Found key [{}] value [{}] in file [{}] using regex [{}]", key, value, file, splitRegex); keyValues.add(new Pair(key, value)); } @@ -314,4 +319,12 @@ protected List> readKeyValuesFromFile(Path file, String spl return keyValues; } + + protected BagitAlgorithmNameToSupportedAlgorithmMapping getNameMapping() { + return nameMapping; + } + + protected void setNameMapping(final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping) { + this.nameMapping = nameMapping; + } } diff --git a/src/main/java/gov/loc/repository/bagit/tasks/CheckIfFileExistsTask.java b/src/main/java/gov/loc/repository/bagit/tasks/CheckIfFileExistsTask.java index c18013bce..5651a3e32 100644 --- a/src/main/java/gov/loc/repository/bagit/tasks/CheckIfFileExistsTask.java +++ b/src/main/java/gov/loc/repository/bagit/tasks/CheckIfFileExistsTask.java @@ -7,12 +7,13 @@ /** * A simple task to check if a file exists on the filesystem. This is thread safe, so many can be called at once. */ +@SuppressWarnings(value = {"PMD.DoNotUseThreads", "PMD.AvoidStringBufferField"}) public class CheckIfFileExistsTask implements Runnable { - private final Path file; - private final StringBuilder messageBuilder; - private final CountDownLatch latch; + private transient final Path file; + private transient final StringBuilder messageBuilder; + private transient final CountDownLatch latch; - public CheckIfFileExistsTask(Path file, StringBuilder messageBuilder, CountDownLatch latch) { + public CheckIfFileExistsTask(final Path file, final StringBuilder messageBuilder, final CountDownLatch latch) { this.file = file; this.messageBuilder = messageBuilder; this.latch = latch; diff --git a/src/main/java/gov/loc/repository/bagit/tasks/CheckManifestHashsTask.java b/src/main/java/gov/loc/repository/bagit/tasks/CheckManifestHashsTask.java index 591daf6ca..53b087ee6 100644 --- a/src/main/java/gov/loc/repository/bagit/tasks/CheckManifestHashsTask.java +++ b/src/main/java/gov/loc/repository/bagit/tasks/CheckManifestHashsTask.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.CountDownLatch; @@ -20,15 +21,16 @@ * Checks a give file to make sure the given checksum hash matches the computed checksum hash. * This is thread safe so you can call many at a time. */ +@SuppressWarnings("PMD.DoNotUseThreads") public class CheckManifestHashsTask implements Runnable { private static final Logger logger = LoggerFactory.getLogger(CheckManifestHashsTask.class); - private final Entry entry; - private final CountDownLatch latch; - private final List exceptions; - private final String algorithm; + private transient final Entry entry; + private transient final CountDownLatch latch; + private transient final List exceptions; + private transient final String algorithm; - public CheckManifestHashsTask(Entry entry, String algorithm, CountDownLatch latch, List exceptions) { + public CheckManifestHashsTask(final Entry entry, final String algorithm, final CountDownLatch latch, final List exceptions) { this.entry = entry; this.algorithm = algorithm; this.latch = latch; @@ -38,19 +40,19 @@ public CheckManifestHashsTask(Entry entry, String algorithm, Count @Override public void run() { try { - MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + final MessageDigest messageDigest = MessageDigest.getInstance(algorithm); checkManifestEntry(entry, messageDigest, algorithm); - } catch (Exception e) { + } catch (IOException | CorruptChecksumException | NoSuchAlgorithmException e) { exceptions.add(e); } latch.countDown(); } - protected static void checkManifestEntry(Entry entry, MessageDigest messageDigest, String algorithm) throws IOException, CorruptChecksumException{ + protected static void checkManifestEntry(final Entry entry, final MessageDigest messageDigest, final String algorithm) throws IOException, CorruptChecksumException{ if(Files.exists(entry.getKey())){ logger.debug("Checking file [{}] to see if checksum matches [{}]", entry.getKey(), entry.getValue()); - InputStream inputStream = Files.newInputStream(entry.getKey(), StandardOpenOption.READ); - String hash = Hasher.hash(inputStream, messageDigest); + final InputStream inputStream = Files.newInputStream(entry.getKey(), StandardOpenOption.READ); + final String hash = Hasher.hash(inputStream, messageDigest); logger.debug("computed hash [{}] for file [{}]", hash, entry.getKey()); if(!hash.equals(entry.getValue())){ throw new CorruptChecksumException("File [" + entry.getKey() + "] is suppose to have a " + algorithm + diff --git a/src/main/java/gov/loc/repository/bagit/util/PathUtils.java b/src/main/java/gov/loc/repository/bagit/util/PathUtils.java index a4f2c5878..f50666f04 100644 --- a/src/main/java/gov/loc/repository/bagit/util/PathUtils.java +++ b/src/main/java/gov/loc/repository/bagit/util/PathUtils.java @@ -2,7 +2,11 @@ import java.nio.file.Path; -public class PathUtils { +public final class PathUtils { + + private PathUtils(){ + //intentionally left blank + } /** * Needed to get rid of findbugs "dodgy code warnings" in regards to getting the filename of a path as a string @@ -10,10 +14,10 @@ public class PathUtils { * @param path the path that you which to get the filename as a string * @return the filename or an empty string */ - public static String getFilename(Path path){ + public static String getFilename(final Path path){ String filename = ""; if(path != null){ - Path filenamePath = path.getFileName(); + final Path filenamePath = path.getFileName(); if(filenamePath != null){ filename = filenamePath.toString(); } @@ -27,7 +31,7 @@ public static String getFilename(Path path){ * @param encoded the encoded filename * @return the decoded filename */ - public static String decodeFilname(String encoded){ + public static String decodeFilname(final String encoded){ return encoded.replaceAll("%0A", "\n").replaceAll("%0D", "\r"); } @@ -36,7 +40,7 @@ public static String decodeFilname(String encoded){ * @param path the path to encode * @return the encoded filename */ - public static String encodeFilename(Path path){ + public static String encodeFilename(final Path path){ return path.toString().replaceAll("\n", "%0A").replaceAll("\r", "%0D"); } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java b/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java index 451576500..01b66f737 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java +++ b/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java @@ -31,6 +31,7 @@ import gov.loc.repository.bagit.exceptions.MissingPayloadDirectoryException; import gov.loc.repository.bagit.exceptions.MissingPayloadManifestException; import gov.loc.repository.bagit.exceptions.PayloadOxumDoesNotExistException; +import gov.loc.repository.bagit.exceptions.VerificationException; import gov.loc.repository.bagit.hash.BagitAlgorithmNameToSupportedAlgorithmMapping; import gov.loc.repository.bagit.hash.StandardBagitAlgorithmNameToSupportedAlgorithmMapping; import gov.loc.repository.bagit.reader.BagReader; @@ -42,6 +43,7 @@ /** * Responsible for verifying if a bag is valid, complete */ +@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public class BagVerifier { private static final Logger logger = LoggerFactory.getLogger(BagVerifier.class); @@ -50,13 +52,13 @@ public class BagVerifier { private static final String DOT_BAGIT_DIR_NAME = ".bagit"; private static final String PAYLOAD_OXUM_REGEX = "\\d+\\.\\d+"; - private BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping; + private final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping; public BagVerifier(){ nameMapping = new StandardBagitAlgorithmNameToSupportedAlgorithmMapping(); } - public BagVerifier(BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ + public BagVerifier(final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ this.nameMapping = nameMapping; } @@ -66,14 +68,14 @@ public BagVerifier(BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping){ * @param bag the {@link Bag} object you wish to check * @return true if the bag can be quickly verified */ - public boolean canQuickVerify(Bag bag){ - String payloadOxum = getPayloadOxum(bag); + public boolean canQuickVerify(final Bag bag){ + final String payloadOxum = getPayloadOxum(bag); logger.debug("Found payload-oxum [{}] for bag [{}]", payloadOxum, bag.getRootDir()); return payloadOxum != null && payloadOxum.matches(PAYLOAD_OXUM_REGEX) && bag.getItemsToFetch().size() == 0; } - protected String getPayloadOxum(Bag bag){ - for(Pair keyValue : bag.getMetadata()){ + protected String getPayloadOxum(final Bag bag){ + for(final Pair keyValue : bag.getMetadata()){ if("Payload-Oxum".equals(keyValue.getKey())){ return keyValue.getValue(); } @@ -93,20 +95,20 @@ protected String getPayloadOxum(Bag bag){ * @throws PayloadOxumDoesNotExistException if the bag does not contain a payload-oxum. * To check, run {@link BagVerifier#canQuickVerify} */ - public void quicklyVerify(Bag bag, boolean ignoreHiddenFiles) throws IOException, InvalidPayloadOxumException{ - String payloadOxum = getPayloadOxum(bag); + public void quicklyVerify(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, InvalidPayloadOxumException{ + final String payloadOxum = getPayloadOxum(bag); if(payloadOxum == null || !payloadOxum.matches(PAYLOAD_OXUM_REGEX)){ throw new PayloadOxumDoesNotExistException("Payload-Oxum does not exist in bag."); } - String[] parts = payloadOxum.split("\\."); + final String[] parts = payloadOxum.split("\\."); logger.debug("Parsing [{}] for the total byte size of the payload oxum", parts[0]); - long totalSize = Long.parseLong(parts[0]); + final long totalSize = Long.parseLong(parts[0]); logger.debug("Parsing [{}] for the number of files to find in the payload directory", parts[1]); - long numberOfFiles = Long.parseLong(parts[1]); + final long numberOfFiles = Long.parseLong(parts[1]); - Path payloadDir = getDataDir(bag); - FileCountAndTotalSizeVistor vistor = new FileCountAndTotalSizeVistor(ignoreHiddenFiles); + final Path payloadDir = getDataDir(bag); + final FileCountAndTotalSizeVistor vistor = new FileCountAndTotalSizeVistor(ignoreHiddenFiles); Files.walkFileTree(payloadDir, vistor); logger.info("supplied payload-oxum: [{}], Calculated payload-oxum: [{}.{}], for payload directory [{}]", payloadOxum, vistor.getTotalSize(), vistor.getCount(), payloadDir); @@ -135,18 +137,19 @@ public void quicklyVerify(Bag bag, boolean ignoreHiddenFiles) throws IOException * @throws FileNotInPayloadDirectoryException if a manifest lists a file but it is not in the payload directory * @throws InterruptedException if the threads are interrupted when checking if all files are listed in manifest(s) * @throws MaliciousManifestException if there is path that is referenced in the manifest that is outside the bag root directory + * @throws VerificationException some other exception happened during processing so capture it here. */ - public void isValid(Bag bag, boolean ignoreHiddenFiles) throws Exception, IOException, MissingPayloadManifestException, MissingBagitFileException, MissingPayloadDirectoryException, FileNotInPayloadDirectoryException, InterruptedException, MaliciousManifestException{ + public void isValid(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, NoSuchAlgorithmException, MissingPayloadManifestException, MissingBagitFileException, MissingPayloadDirectoryException, FileNotInPayloadDirectoryException, InterruptedException, MaliciousManifestException, CorruptChecksumException, VerificationException{ logger.info("Checking if the bag with root directory [{}] is valid.", bag.getRootDir()); isComplete(bag, ignoreHiddenFiles); logger.debug("Checking payload manifest(s) checksums"); - for(Manifest payloadManifest : bag.getPayLoadManifests()){ + for(final Manifest payloadManifest : bag.getPayLoadManifests()){ checkHashes(payloadManifest); } logger.debug("Checking tag manifest(s) checksums"); - for(Manifest tagManifest : bag.getTagManifests()){ + for(final Manifest tagManifest : bag.getTagManifests()){ checkHashes(tagManifest); } } @@ -157,22 +160,29 @@ public void isValid(Bag bag, boolean ignoreHiddenFiles) throws Exception, IOExce * @param manifest list of file and their hash * * @throws CorruptChecksumException if any of the files computed checksum is different than the manifest supplied checksum + * @throws InterruptedException if the thread is interrupted + * @throws VerificationException if there is some other exception while checking the checksum(s) */ - protected void checkHashes(Manifest manifest) throws Exception{ - ExecutorService executor = Executors.newCachedThreadPool(); + protected void checkHashes(final Manifest manifest) throws CorruptChecksumException, InterruptedException, VerificationException{ + final ExecutorService executor = Executors.newCachedThreadPool(); final CountDownLatch latch = new CountDownLatch( manifest.getFileToChecksumMap().size()); final List exceptions = new ArrayList<>(); //TODO maybe return all of these at some point... - for(Entry entry : manifest.getFileToChecksumMap().entrySet()){ + for(final Entry entry : manifest.getFileToChecksumMap().entrySet()){ executor.execute(new CheckManifestHashsTask(entry, manifest.getAlgorithm().getMessageDigestName(), latch, exceptions)); } latch.await(); executor.shutdown(); - if(exceptions.size() > 0){ - logger.debug("[{}] hashes don't match, but I can only return one exception", exceptions.size()); - throw exceptions.get(0); + if(!exceptions.isEmpty()){ + final Exception e = exceptions.get(0); + if(e instanceof CorruptChecksumException){ + logger.debug("[{}] hashes don't match, but I can only return one exception", exceptions.size()); + throw (CorruptChecksumException)e; + } + + throw new VerificationException(e); } } @@ -198,12 +208,12 @@ protected void checkHashes(Manifest manifest) throws Exception{ * @throws InterruptedException if the threads are interrupted when checking if all files are listed in manifest(s) * @throws MaliciousManifestException if there is path that is referenced in the manifest that is outside the bag root directory */ - public void isComplete(Bag bag, boolean ignoreHiddenFiles) throws + public void isComplete(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, MissingPayloadManifestException, MissingBagitFileException, MissingPayloadDirectoryException, FileNotInPayloadDirectoryException, InterruptedException, MaliciousManifestException{ logger.info("Checking if the bag with root directory [{}] is complete.", bag.getRootDir()); - Path dataDir = getDataDir(bag); + final Path dataDir = getDataDir(bag); checkFetchItemsExist(bag.getItemsToFetch(), bag.getRootDir()); @@ -213,12 +223,12 @@ public void isComplete(Bag bag, boolean ignoreHiddenFiles) throws checkIfAtLeastOnePayloadManifestsExist(bag.getRootDir(), bag.getVersion()); - Set allFilesListedInManifests = getAllFilesListedInManifests(bag); + final Set allFilesListedInManifests = getAllFilesListedInManifests(bag); checkAllFilesListedInManifestExist(allFilesListedInManifests); checkAllFilesInPayloadDirAreListedInAManifest(allFilesListedInManifests, dataDir, ignoreHiddenFiles); } - protected Path getDataDir(Bag bag){ + protected Path getDataDir(final Bag bag){ if(bag.getVersion().compareTo(new Version(0, 98)) >= 0){ //is it a .bagit version? return bag.getRootDir(); } @@ -226,17 +236,17 @@ protected Path getDataDir(Bag bag){ return bag.getRootDir().resolve(PAYLOAD_DIR_NAME); } - protected void checkFetchItemsExist(List items, Path bagDir) throws FileNotInPayloadDirectoryException{ + protected void checkFetchItemsExist(final List items, final Path bagDir) throws FileNotInPayloadDirectoryException{ logger.info("Checking if all [{}] items in fetch.txt exist in the [{}]", items.size(), bagDir); - for(FetchItem item : items){ - Path file = bagDir.resolve(item.path); + for(final FetchItem item : items){ + final Path file = bagDir.resolve(item.path); if(!Files.exists(file)){ throw new FileNotInPayloadDirectoryException("Fetch item " + item + " has not been fetched!"); } } } - protected void checkBagitFileExists(Path rootDir, Version version) throws MissingBagitFileException{ + protected void checkBagitFileExists(final Path rootDir, final Version version) throws MissingBagitFileException{ logger.info("Checking if bagit.txt file exists"); Path bagitFile = rootDir.resolve("bagit.txt"); //@Incubating @@ -249,16 +259,16 @@ protected void checkBagitFileExists(Path rootDir, Version version) throws Missin } } - protected void checkPayloadDirectoryExists(Bag bag) throws MissingPayloadDirectoryException{ + protected void checkPayloadDirectoryExists(final Bag bag) throws MissingPayloadDirectoryException{ logger.info("Checking if special payload directory exists (only for version 0.97 and earlier)"); - Path dataDir = getDataDir(bag); + final Path dataDir = getDataDir(bag); if(!Files.exists(dataDir)){ throw new MissingPayloadDirectoryException("File [" + dataDir + "] should exist but it doesn't"); } } - protected void checkIfAtLeastOnePayloadManifestsExist(Path rootDir, Version version) throws MissingPayloadManifestException, IOException{ + protected void checkIfAtLeastOnePayloadManifestsExist(final Path rootDir, final Version version) throws MissingPayloadManifestException, IOException{ logger.info("Checking if there is at least one payload manifest in [{}]", rootDir); boolean hasAtLeastOneManifest = false; @@ -268,7 +278,7 @@ protected void checkIfAtLeastOnePayloadManifestsExist(Path rootDir, Version vers directoryStream = Files.newDirectoryStream(rootDir.resolve(DOT_BAGIT_DIR_NAME)); } - for(Path path : directoryStream){ + for(final Path path : directoryStream){ if(PathUtils.getFilename(path).startsWith("manifest-")){ logger.debug("Found payload manifest file [{}]", path.getFileName()); hasAtLeastOneManifest = true; @@ -281,9 +291,9 @@ protected void checkIfAtLeastOnePayloadManifestsExist(Path rootDir, Version vers } - protected Set getAllFilesListedInManifests(Bag bag) throws IOException, MaliciousManifestException{ + protected Set getAllFilesListedInManifests(final Bag bag) throws IOException, MaliciousManifestException{ logger.debug("Getting all files listed in the manifest(s)"); - Set filesListedInManifests = new HashSet<>(); + final Set filesListedInManifests = new HashSet<>(); DirectoryStream directoryStream = Files.newDirectoryStream(bag.getRootDir()); //@Incubating @@ -291,13 +301,13 @@ protected Set getAllFilesListedInManifests(Bag bag) throws IOException, Ma directoryStream = Files.newDirectoryStream(bag.getRootDir().resolve(DOT_BAGIT_DIR_NAME)); } - BagReader reader = new BagReader(nameMapping); + final BagReader reader = new BagReader(nameMapping); - for(Path path : directoryStream){ - String filename = PathUtils.getFilename(path); + for(final Path path : directoryStream){ + final String filename = PathUtils.getFilename(path); if(filename.startsWith("tagmanifest-") || filename.startsWith("manifest-")){ logger.debug("Getting files and checksums listed in [{}]", path); - Manifest manifest = reader.readManifest(path, bag.getRootDir()); + final Manifest manifest = reader.readManifest(path, bag.getRootDir()); filesListedInManifests.addAll(manifest.getFileToChecksumMap().keySet()); } } @@ -305,29 +315,33 @@ protected Set getAllFilesListedInManifests(Bag bag) throws IOException, Ma return filesListedInManifests; } - protected void checkAllFilesListedInManifestExist(Set files) throws FileNotInPayloadDirectoryException, InterruptedException{ - ExecutorService executor = Executors.newCachedThreadPool(); + protected void checkAllFilesListedInManifestExist(final Set files) throws FileNotInPayloadDirectoryException, InterruptedException{ + final ExecutorService executor = Executors.newCachedThreadPool(); final CountDownLatch latch = new CountDownLatch(files.size()); final StringBuilder messageBuilder = new StringBuilder(); logger.debug("Checking if all files listed in the manifest(s) exist"); - for(Path file : files){ + for(final Path file : files){ executor.execute(new CheckIfFileExistsTask(file, messageBuilder, latch)); } latch.await(); executor.shutdown(); - String missingFilesMessage = messageBuilder.toString(); + final String missingFilesMessage = messageBuilder.toString(); if(!missingFilesMessage.isEmpty()){ throw new FileNotInPayloadDirectoryException(missingFilesMessage); } } - protected void checkAllFilesInPayloadDirAreListedInAManifest(Set filesListedInManifests, Path payloadDir, boolean ignoreHiddenFiles) throws IOException{ + protected void checkAllFilesInPayloadDirAreListedInAManifest(final Set filesListedInManifests, final Path payloadDir, final boolean ignoreHiddenFiles) throws IOException{ logger.debug("Checking if all payload files (files in {} dir) are listed in at least one manifest", payloadDir); if(Files.exists(payloadDir)){ Files.walkFileTree(payloadDir, new PayloadFileExistsInManifestVistor(filesListedInManifests, ignoreHiddenFiles)); } } + + protected BagitAlgorithmNameToSupportedAlgorithmMapping getNameMapping() { + return nameMapping; + } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java b/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java index 0c99baab7..6bd10b5fc 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java @@ -16,16 +16,16 @@ public class FileCountAndTotalSizeVistor extends SimpleFileVisitor { private static final Logger logger = LoggerFactory.getLogger(FileCountAndTotalSizeVistor.class); - private final boolean ignoreHiddenFiles; - private long totalSize = 0; - private long count = 0; + private transient final boolean ignoreHiddenFiles; + private transient long totalSize; + private transient long count; - public FileCountAndTotalSizeVistor(boolean ignoreHiddenFiles) { + public FileCountAndTotalSizeVistor(final boolean ignoreHiddenFiles) { this.ignoreHiddenFiles = ignoreHiddenFiles; } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if(ignoreHiddenFiles && Files.isHidden(dir)){ logger.debug("Skipping {} cause ignore hidden files/directories", dir); return FileVisitResult.SKIP_SUBTREE; @@ -35,13 +35,13 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException{ + public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) throws IOException{ if(!ignoreHiddenFiles && Files.isHidden(path) && !path.endsWith(".keep")){ logger.debug("Skipping [{}] since we are ignoring hidden files", path); } else{ count++; - long size = Files.size(path); + final long size = Files.size(path); logger.debug("File [{}] hash a size of [{}] bytes", path, size); totalSize += size; } diff --git a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInManifestVistor.java b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInManifestVistor.java index 8c40a7226..4612d2c14 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInManifestVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInManifestVistor.java @@ -18,16 +18,16 @@ */ public class PayloadFileExistsInManifestVistor extends SimpleFileVisitor { private static final Logger logger = LoggerFactory.getLogger(PayloadFileExistsInManifestVistor.class); - private final Set filesListedInManifests; - private final boolean ignoreHiddenFiles; + private transient final Set filesListedInManifests; + private transient final boolean ignoreHiddenFiles; - public PayloadFileExistsInManifestVistor(Set filesListedInManifests, boolean ignoreHiddenFiles) { + public PayloadFileExistsInManifestVistor(final Set filesListedInManifests, final boolean ignoreHiddenFiles) { this.filesListedInManifests = filesListedInManifests; this.ignoreHiddenFiles = ignoreHiddenFiles; } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if(ignoreHiddenFiles && Files.isHidden(dir)){ logger.debug("Skipping [{}] cause it is a hidden folder", dir); return FileVisitResult.SKIP_SUBTREE; @@ -37,7 +37,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th } @Override - public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)throws FileNotInManifestException{ + public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs)throws FileNotInManifestException{ if(Files.isRegularFile(path) && !filesListedInManifests.contains(path)){ throw new FileNotInManifestException("File " + path + " is in the payload directory but isn't listed in any of the manifests"); } diff --git a/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java b/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java index 6220801bc..65555397b 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java @@ -28,12 +28,15 @@ /** * responsible for writing out a bag. */ -public class BagWriter { +@SuppressWarnings(value = {"PMD.TooManyMethods", "PMD.AvoidInstantiatingObjectsInLoops"}) //TODO refactor to remove methods? +public final class BagWriter { private static final Logger logger = LoggerFactory.getLogger(BagWriter.class); private static final Version VERSION_0_98 = new Version(0, 98); private static final Version VERSION_0_95 = new Version(0, 95); - private BagWriter(){} + private BagWriter(){ + //intentionally left empty + } /** * Write the bag out to the specified directory. @@ -47,8 +50,8 @@ private BagWriter(){} * @throws IOException if there is a problem writing a file * @throws NoSuchAlgorithmException when trying to generate a {@link MessageDigest} which is used during update. */ - public static void write(Bag bag, Path outputDir) throws IOException, NoSuchAlgorithmException{ - Path bagitDir = writeVersionDependentPayloadFiles(bag, outputDir); + public static void write(final Bag bag, final Path outputDir) throws IOException, NoSuchAlgorithmException{ + final Path bagitDir = writeVersionDependentPayloadFiles(bag, outputDir); writeBagitFile(bag.getVersion(), bag.getFileEncoding(), bagitDir); writePayloadManifests(bag.getPayLoadManifests(), bagitDir, bag.getRootDir(), bag.getFileEncoding()); @@ -61,13 +64,13 @@ public static void write(Bag bag, Path outputDir) throws IOException, NoSuchAlgo } if(bag.getTagManifests().size() > 0){ writeAdditionalTagPayloadFiles(bag.getTagManifests(), bagitDir, bag.getRootDir()); - Set updatedTagManifests = updateTagManifests(bag, outputDir); + final Set updatedTagManifests = updateTagManifests(bag, outputDir); bag.setTagManifests(updatedTagManifests); writeTagManifests(updatedTagManifests, bagitDir, outputDir, bag.getFileEncoding()); } } - protected static Path writeVersionDependentPayloadFiles(Bag bag, Path outputDir) throws IOException{ + private static Path writeVersionDependentPayloadFiles(final Bag bag, final Path outputDir) throws IOException{ Path bagitDir = outputDir; //@Incubating if(VERSION_0_98.compareTo(bag.getVersion()) <= 0){ @@ -76,7 +79,7 @@ protected static Path writeVersionDependentPayloadFiles(Bag bag, Path outputDir) writePayloadFiles(bag.getPayLoadManifests(), outputDir, bag.getRootDir()); } else{ - Path dataDir = outputDir.resolve("data"); + final Path dataDir = outputDir.resolve("data"); Files.createDirectories(dataDir); writePayloadFiles(bag.getPayLoadManifests(), dataDir, bag.getRootDir().resolve("data")); } @@ -93,17 +96,17 @@ protected static Path writeVersionDependentPayloadFiles(Bag bag, Path outputDir) * * @throws IOException if there was a problem writing the file */ - public static void writeBagitFile(Version version, Charset encoding, Path outputDir) throws IOException{ - Path bagitPath = outputDir.resolve("bagit.txt"); + public static void writeBagitFile(final Version version, final Charset encoding, final Path outputDir) throws IOException{ + final Path bagitPath = outputDir.resolve("bagit.txt"); logger.debug("Writing bagit.txt file to [{}]", outputDir); - String firstLine = "BagIt-Version : " + version + System.lineSeparator(); + final String firstLine = "BagIt-Version : " + version + System.lineSeparator(); logger.debug("Writing line [{}] to [{}]", firstLine, bagitPath); Files.write(bagitPath, firstLine.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); - String secondLine = "Tag-File-Character-Encoding : " + encoding + System.lineSeparator(); + final String secondLine = "Tag-File-Character-Encoding : " + encoding + System.lineSeparator(); logger.debug("Writing line [{}] to [{}]", secondLine, bagitPath); Files.write(bagitPath, secondLine.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.APPEND); } @@ -117,15 +120,15 @@ public static void writeBagitFile(Version version, Charset encoding, Path output * * @throws IOException if there was a problem writing a file */ - public static void writePayloadFiles(Set payloadManifests, Path outputDir, Path bagDataDir) throws IOException{ + public static void writePayloadFiles(final Set payloadManifests, final Path outputDir, final Path bagDataDir) throws IOException{ logger.info("Writing payload files"); - for(Manifest payloadManifest : payloadManifests){ - for(Path payloadFile : payloadManifest.getFileToChecksumMap().keySet()){ - Path relativePayloadPath = bagDataDir.relativize(payloadFile); + for(final Manifest payloadManifest : payloadManifests){ + for(final Path payloadFile : payloadManifest.getFileToChecksumMap().keySet()){ + final Path relativePayloadPath = bagDataDir.relativize(payloadFile); - Path writeToPath = outputDir.resolve(relativePayloadPath); + final Path writeToPath = outputDir.resolve(relativePayloadPath); logger.debug("Writing payload file [{}] to [{}]", payloadFile, writeToPath); - Path parent = writeToPath.getParent(); + final Path parent = writeToPath.getParent(); if(parent != null){ Files.createDirectories(parent); } @@ -144,22 +147,22 @@ public static void writePayloadFiles(Set payloadManifests, Path output * * @throws IOException if there was a problem writing a file */ - public static void writePayloadManifests(Set manifests, Path outputDir, Path bagitRootDir, Charset charsetName) throws IOException{ + public static void writePayloadManifests(final Set manifests, final Path outputDir, final Path bagitRootDir, final Charset charsetName) throws IOException{ logger.info("Writing payload manifest(s)"); writeManifests(manifests, outputDir, bagitRootDir, "manifest-", charsetName); } - protected static Set updateTagManifests(Bag bag, Path newBagRootDir) throws NoSuchAlgorithmException, IOException{ - Set newManifests = new HashSet<>(); + private static Set updateTagManifests(final Bag bag, final Path newBagRootDir) throws NoSuchAlgorithmException, IOException{ + final Set newManifests = new HashSet<>(); - for(Manifest tagManifest : bag.getTagManifests()){ - Manifest newManifest = new Manifest(tagManifest.getAlgorithm()); + for(final Manifest tagManifest : bag.getTagManifests()){ + final Manifest newManifest = new Manifest(tagManifest.getAlgorithm()); - for(Path originalPath : tagManifest.getFileToChecksumMap().keySet()){ - Path relativePath = bag.getRootDir().relativize(originalPath); - Path pathToUpdate = newBagRootDir.resolve(relativePath); - MessageDigest messageDigest = MessageDigest.getInstance(tagManifest.getAlgorithm().getMessageDigestName()); - String newChecksum = Hasher.hash(Files.newInputStream(pathToUpdate), messageDigest); + for(final Path originalPath : tagManifest.getFileToChecksumMap().keySet()){ + final Path relativePath = bag.getRootDir().relativize(originalPath); + final Path pathToUpdate = newBagRootDir.resolve(relativePath); + final MessageDigest messageDigest = MessageDigest.getInstance(tagManifest.getAlgorithm().getMessageDigestName()); + final String newChecksum = Hasher.hash(Files.newInputStream(pathToUpdate), messageDigest); newManifest.getFileToChecksumMap().put(pathToUpdate, newChecksum); } @@ -179,21 +182,21 @@ protected static Set updateTagManifests(Bag bag, Path newBagRootDir) t * * @throws IOException if there was a problem writing a file */ - public static void writeTagManifests(Set tagManifests, Path outputDir, Path bagitRootDir, Charset charsetName) throws IOException{ + public static void writeTagManifests(final Set tagManifests, final Path outputDir, final Path bagitRootDir, final Charset charsetName) throws IOException{ logger.info("Writing tag manifest(s)"); writeManifests(tagManifests, outputDir, bagitRootDir, "tagmanifest-", charsetName); } - protected static void writeManifests(Set manifests, Path outputDir, Path relativeTo, String filenameBase, Charset charsetName) throws IOException{ - for(Manifest manifest : manifests){ - Path manifestPath = outputDir.resolve(filenameBase + manifest.getAlgorithm().getBagitName() + ".txt"); + private static void writeManifests(final Set manifests, final Path outputDir, final Path relativeTo, final String filenameBase, final Charset charsetName) throws IOException{ + for(final Manifest manifest : manifests){ + final Path manifestPath = outputDir.resolve(filenameBase + manifest.getAlgorithm().getBagitName() + ".txt"); logger.debug("Writing manifest to [{}]", manifestPath); Files.deleteIfExists(manifestPath); Files.createFile(manifestPath); - for(Entry entry : manifest.getFileToChecksumMap().entrySet()){ - String line = entry.getValue() + " " + + for(final Entry entry : manifest.getFileToChecksumMap().entrySet()){ + final String line = entry.getValue() + " " + PathUtils.encodeFilename(relativeTo.relativize(entry.getKey())) + System.lineSeparator(); logger.debug("Writing [{}] to [{}]", line, manifestPath); Files.write(manifestPath, line.getBytes(charsetName), @@ -202,12 +205,12 @@ protected static void writeManifests(Set manifests, Path outputDir, Pa } } - protected static void writeAdditionalTagPayloadFiles(Set manifests, Path outputDir, Path bagRootDir) throws IOException{ - for(Manifest manifest : manifests){ - for(Entry entry : manifest.getFileToChecksumMap().entrySet()){ - Path relativeLocation = bagRootDir.relativize(entry.getKey()); - Path writeTo = outputDir.resolve(relativeLocation); - Path writeToParent = writeTo.getParent(); + private static void writeAdditionalTagPayloadFiles(final Set manifests, final Path outputDir, final Path bagRootDir) throws IOException{ + for(final Manifest manifest : manifests){ + for(final Entry entry : manifest.getFileToChecksumMap().entrySet()){ + final Path relativeLocation = bagRootDir.relativize(entry.getKey()); + final Path writeTo = outputDir.resolve(relativeLocation); + final Path writeToParent = writeTo.getParent(); if(!Files.exists(writeTo) && writeToParent != null){ Files.createDirectories(writeToParent); Files.copy(entry.getKey(), writeTo); @@ -226,7 +229,7 @@ protected static void writeAdditionalTagPayloadFiles(Set manifests, Pa * * @throws IOException if there was a problem writing a file */ - public static void writeBagitInfoFile(List> metadata, Version version, Path outputDir, Charset charsetName) throws IOException{ + public static void writeBagitInfoFile(final List> metadata, final Version version, final Path outputDir, final Charset charsetName) throws IOException{ Path bagInfoFilePath = outputDir.resolve("bag-info.txt"); if(VERSION_0_95.compareTo(version) >= 0){ bagInfoFilePath = outputDir.resolve("package-info.txt"); @@ -235,8 +238,8 @@ public static void writeBagitInfoFile(List> metadata, Versi Files.deleteIfExists(bagInfoFilePath); - for(Pair entry : metadata){ - String line = entry.getKey() + " : " + entry.getValue() + System.lineSeparator(); + for(final Pair entry : metadata){ + final String line = entry.getKey() + " : " + entry.getValue() + System.lineSeparator(); logger.debug("Writing [{}] to [{}]", line, bagInfoFilePath); Files.write(bagInfoFilePath, line.getBytes(charsetName), StandardOpenOption.APPEND, StandardOpenOption.CREATE); @@ -252,12 +255,12 @@ public static void writeBagitInfoFile(List> metadata, Versi * * @throws IOException if there was a problem writing a file */ - public static void writeFetchFile(List itemsToFetch, Path outputDir, Charset charsetName) throws IOException{ + public static void writeFetchFile(final List itemsToFetch, final Path outputDir, final Charset charsetName) throws IOException{ logger.debug("Writing fetch.txt to [{}]", outputDir); - Path fetchFilePath = outputDir.resolve("fetch.txt"); + final Path fetchFilePath = outputDir.resolve("fetch.txt"); - for(FetchItem item : itemsToFetch){ - String line = item.toString(); + for(final FetchItem item : itemsToFetch){ + final String line = item.toString(); logger.debug("Writing [{}] to [{}]", line, fetchFilePath); Files.write(fetchFilePath, line.getBytes(charsetName), StandardOpenOption.APPEND, StandardOpenOption.CREATE); }