From 75cedbe9688c47c007334ca7ff39bbbbb882bbfe Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 27 Apr 2017 07:20:37 -0400 Subject: [PATCH 1/5] refs #89 - separate out hard coded text into resource bundle so that the local language can be used --- code-quality.gradle | 8 +- .../bagit/conformance/BagLinter.java | 18 +- .../bagit/conformance/BagProfileChecker.java | 37 +-- .../bagit/conformance/BagitWarning.java | 45 ++-- .../bagit/conformance/EncodingChecker.java | 4 +- .../bagit/conformance/ManifestChecker.java | 36 +-- .../bagit/conformance/MetadataChecker.java | 4 +- .../bagit/conformance/VersionChecker.java | 4 +- .../profile/BagitProfileDeserializer.java | 32 +-- .../AbstractCreateManifestsVistor.java | 8 +- .../repository/bagit/creator/BagCreator.java | 17 +- .../exceptions/CorruptChecksumException.java | 8 +- .../UnparsableVersionException.java | 6 +- .../UnsupportedAlgorithmException.java | 6 +- .../BagitVersionIsNotAcceptableException.java | 10 +- .../FetchFileNotAllowedException.java | 8 +- ...etatdataValueIsNotAcceptableException.java | 8 +- ...uiredMetadataFieldNotPresentException.java | 6 +- .../RequiredTagFileNotPresentException.java | 6 +- .../gov/loc/repository/bagit/hash/Hasher.java | 4 +- ...orithmNameToSupportedAlgorithmMapping.java | 4 +- .../bagit/reader/BagitTextFileReader.java | 17 +- .../repository/bagit/reader/FetchReader.java | 6 +- .../bagit/reader/KeyValueReader.java | 21 +- .../bagit/reader/ManifestReader.java | 10 +- .../bagit/reader/MetadataReader.java | 8 +- .../bagit/reader/TagFileReader.java | 18 +- ...actPayloadFileExistsInManifestsVistor.java | 10 +- .../repository/bagit/verify/BagVerifier.java | 14 +- .../bagit/verify/CheckIfFileExistsTask.java | 7 +- ...Task.java => CheckManifestHashesTask.java} | 13 +- .../verify/FileCountAndTotalSizeVistor.java | 9 +- .../bagit/verify/MandatoryVerifier.java | 19 +- ...PayloadFileExistsInAllManifestsVistor.java | 7 +- ...dFileExistsInAtLeastOneManifestVistor.java | 5 +- .../bagit/verify/PayloadVerifier.java | 17 +- .../bagit/verify/QuickVerifier.java | 19 +- .../repository/bagit/writer/BagWriter.java | 16 +- .../bagit/writer/BagitFileWriter.java | 8 +- .../repository/bagit/writer/FetchWriter.java | 8 +- .../bagit/writer/ManifestWriter.java | 10 +- .../bagit/writer/MetadataWriter.java | 6 +- .../bagit/writer/PayloadWriter.java | 6 +- src/main/resources/MessageBundle.properties | 214 ++++++++++++++++++ .../conformance/ManifestCheckerTest.java | 4 +- 45 files changed, 534 insertions(+), 217 deletions(-) rename src/main/java/gov/loc/repository/bagit/verify/{CheckManifestHashsTask.java => CheckManifestHashesTask.java} (77%) create mode 100644 src/main/resources/MessageBundle.properties diff --git a/code-quality.gradle b/code-quality.gradle index e49624404..974fc9e48 100644 --- a/code-quality.gradle +++ b/code-quality.gradle @@ -79,10 +79,10 @@ jacocoTestReport { cpdCheck { source = sourceSets.main.allJava -// reports { -// text.enabled = true -// xml.enabled = false -// } + reports { + text.enabled = true + xml.enabled = false + } } dependencyCheck { diff --git a/src/main/java/gov/loc/repository/bagit/conformance/BagLinter.java b/src/main/java/gov/loc/repository/bagit/conformance/BagLinter.java index 6add61741..aa82a32a5 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/BagLinter.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/BagLinter.java @@ -11,6 +11,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -40,6 +41,7 @@ */ public final class BagLinter { private static final Logger logger = LoggerFactory.getLogger(BagLinter.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private static final Version VERSION_1_0 = new Version(1,0); private BagLinter(){ @@ -117,16 +119,16 @@ public static Set lintBag(final Path rootDir, final Collection bagitInfo = BagitTextFileReader.readBagitTextFile(bagitFile); - logger.debug("Checking encoding problems."); + logger.info(messages.getString("checking_encoding_problems")); EncodingChecker.checkEncoding(bagitInfo.getValue(), warnings, warningsToIgnore); - logger.debug("checking for latest version."); + logger.info(messages.getString("checking_latest_version")); VersionChecker.checkVersion(bagitInfo.getKey(), warnings, warningsToIgnore); - logger.debug("checking manifests for problems."); + logger.info(messages.getString("checking_manifest_problems")); ManifestChecker.checkManifests(bagitDir, bagitInfo.getValue(), warnings, warningsToIgnore); - logger.debug("checking bag metadata for problems."); + logger.info(messages.getString("checking_metadata_problems")); MetadataChecker.checkBagMetadata(bagitDir, bagitInfo.getValue(), warnings, warningsToIgnore); return warnings; @@ -134,11 +136,11 @@ public static Set lintBag(final Path rootDir, final Collection warnings, final Collection warningsToIgnore) throws InvalidBagMetadataException, IOException, UnparsableVersionException{ if(warningsToIgnore.contains(BagitWarning.EXTRA_LINES_IN_BAGIT_FILES)){ - logger.debug("skipping check for extra lines in bagit files"); + logger.debug(messages.getString("skipping_check_extra_lines")); return; } - logger.debug("checking if [{}] contains more than 2 lines"); + logger.debug(messages.getString("checking_extra_lines")); final List> pairs = KeyValueReader.readKeyValuesFromFile(bagitFile, ":", StandardCharsets.UTF_8); for(final SimpleImmutableEntry pair : pairs){ @@ -146,9 +148,7 @@ private static void checkForExtraLines(final Path bagitFile, final Collection 2 && version.isOlder(VERSION_1_0)){ - logger.warn("The bagit specification states that the bagit.txt file must contain exactly 2 lines. " - + "However we found {} lines, some implementations will " - + "ignore this but may cause imcompatibility issues with other tools.", pairs.size()); + logger.warn(messages.getString("extra_lines_warning"), pairs.size()); warnings.add(BagitWarning.EXTRA_LINES_IN_BAGIT_FILES); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/BagProfileChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/BagProfileChecker.java index f72ee4a86..1970c30e9 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/BagProfileChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/BagProfileChecker.java @@ -8,10 +8,12 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; @@ -37,6 +39,7 @@ */ public final class BagProfileChecker { private static final Logger logger = LoggerFactory.getLogger(BagProfileChecker.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagProfileChecker(){ //intentionally left empty @@ -75,8 +78,7 @@ public static void bagConformsToProfile(final InputStream jsonProfile, final Bag requiredManifestsExist(bag.getTagManifests(), profile.getTagManifestTypesRequired(), false); if(!profile.getAcceptableBagitVersions().contains(bag.getVersion().toString())){ - throw new BagitVersionIsNotAcceptableException("Version [" + bag.getVersion().toString() + "] is not in the acceptable list of " + - profile.getAcceptableBagitVersions()); + throw new BagitVersionIsNotAcceptableException(messages.getString("bagit_version_not_acceptable_error"), bag.getVersion(), profile.getAcceptableBagitVersions()); } requiredTagFilesExist(bag.getRootDir(), profile.getTagFilesRequired()); @@ -92,9 +94,9 @@ private static BagitProfile parseBagitProfile(final InputStream jsonProfile) thr } private static void checkFetch(final Path rootDir, final boolean allowFetchFile, final List itemsToFetch) throws FetchFileNotAllowedException{ - logger.debug("Checking if the fetch file is allowed for bag [{}]", rootDir); + logger.debug(messages.getString("checking_fetch_file_allowed"), rootDir); if(!allowFetchFile && !itemsToFetch.isEmpty()){ - throw new FetchFileNotAllowedException("Fetch File was found in bag [" + rootDir + "]"); + throw new FetchFileNotAllowedException(messages.getString("fetch_file_not_allowed_error"), rootDir); } } @@ -104,19 +106,19 @@ private static void checkMetadata(final Metadata bagMetadata, final Map bagInfoEntryRequirement : bagInfoEntryRequirements.entrySet()){ final boolean metadataContainsKey = bagMetadata.contains(bagInfoEntryRequirement.getKey()); - logger.debug("Checking if [{}] is required in the bag metadata", bagInfoEntryRequirement.getKey()); + logger.debug(messages.getString("checking_metadata_entry_required"), bagInfoEntryRequirement.getKey()); //is it required and not there? if(bagInfoEntryRequirement.getValue().isRequired() && !metadataContainsKey){ - throw new RequiredMetadataFieldNotPresentException("Profile specifies metadata field [" + bagInfoEntryRequirement.getKey() + "] is required but was not found!"); + throw new RequiredMetadataFieldNotPresentException(messages.getString("required_metadata_field_not_present_error"), bagInfoEntryRequirement.getKey()); } //a size of zero implies that all values are acceptable if(!bagInfoEntryRequirement.getValue().getAcceptableValues().isEmpty()){ - logger.debug("Checking if all the values listed for [{}] are acceptable", bagInfoEntryRequirement.getKey()); + logger.debug(messages.getString("check_values_acceptable"), bagInfoEntryRequirement.getKey()); for(final String metadataValue : bagMetadata.get(bagInfoEntryRequirement.getKey())){ if(!bagInfoEntryRequirement.getValue().getAcceptableValues().contains(metadataValue)){ - throw new MetatdataValueIsNotAcceptableException("Profile specifies that acceptable values for [" + bagInfoEntryRequirement.getKey() + - "] are " + bagInfoEntryRequirement.getValue().getAcceptableValues() + " but found [" + metadataValue + "]"); + throw new MetatdataValueIsNotAcceptableException(messages.getString("metadata_value_not_acceptable_error"), + bagInfoEntryRequirement.getKey(), bagInfoEntryRequirement.getValue().getAcceptableValues(), metadataValue); } } } @@ -126,7 +128,7 @@ private static void checkMetadata(final Metadata bagMetadata, final Map manifests, final List requiredManifestTypes, final boolean isPayloadManifest) throws RequiredManifestNotPresentException{ final Set manifestTypesPresent = new HashSet<>(); - logger.debug("Checking if all the required manifests are present"); + logger.debug(messages.getString("check_required_manifests_present")); for(final Manifest manifest : manifests){ manifestTypesPresent.add(manifest.getAlgorithm().getBagitName()); @@ -134,10 +136,13 @@ private static void requiredManifestsExist(final Set manifests, final for(final String requiredManifestType : requiredManifestTypes){ if(!manifestTypesPresent.contains(requiredManifestType)){ - final StringBuilder sb = new StringBuilder(25); - sb.append("Required "); - if(isPayloadManifest){ sb.append("tag");} - sb.append("manifest type [").append(requiredManifestType).append("] was not present"); + final StringBuilder sb = new StringBuilder(); + if(isPayloadManifest){ sb.append("tag"); + sb.append(MessageFormatter.format(messages.getString("required_tag_manifest_type_not_present"), requiredManifestType).getMessage()); + } + else{ + sb.append(MessageFormatter.format(messages.getString("required_manifest_type_not_present"), requiredManifestType).getMessage()); + } throw new RequiredManifestNotPresentException(sb.toString()); } @@ -146,12 +151,12 @@ private static void requiredManifestsExist(final Set manifests, final private static void requiredTagFilesExist(final Path rootDir, final List requiredTagFilePaths) throws RequiredTagFileNotPresentException{ Path requiredTagFile; - logger.debug("Checking if all the required tag files exist"); + logger.debug(messages.getString("checking_required_tag_file_exists")); for(final String requiredTagFilePath : requiredTagFilePaths){ requiredTagFile = rootDir.resolve(requiredTagFilePath); if(!Files.exists(requiredTagFile)){ - throw new RequiredTagFileNotPresentException("Required tag file [" + requiredTagFilePath + "] was not found"); + throw new RequiredTagFileNotPresentException(messages.getString("required_tag_file_not_found_error"), requiredTagFilePath); } } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/BagitWarning.java b/src/main/java/gov/loc/repository/bagit/conformance/BagitWarning.java index 34084afa1..3981982ff 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/BagitWarning.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/BagitWarning.java @@ -1,42 +1,35 @@ package gov.loc.repository.bagit.conformance; +import java.util.ResourceBundle; + /** * The BagIt specification is very flexible in what it allows. * This leads to situations where something may be technically allowed, but should be discouraged. * This class is for that purpose, to allow reporting of these allowed but discouraged situations to the user. */ public enum BagitWarning { - BAG_WITHIN_A_BAG("A data directory can contain anything," - + " including another bag. However it would be better to merge the bags together."), - DIFFERENT_CASE("The bag contains two files that differ only in case. " - + "This can cause problems on a filesystem like the one used by apple (HFS)."), - DIFFERENT_NORMALIZATION("The bag contains two files that differ only in the normalization. " - + "This can cause verification to fail on some systems, and general user confusion."), - EXTRA_LINES_IN_BAGIT_FILES("The bagit specification says it must only contain 2 lines. " - + "However, some implementations have decided to ignore this which may cause compatibility issues"), - LEADING_DOT_SLASH("A manifest lists all data files as relative to the bag root directory," - + " it is superfluous to therefore specify it with a dot."), - NON_STANDARD_ALGORITHM("The checksum algorithm used does not come standard with the Java runtime. Consider using SHA512 instead."), - MD5SUM_TOOL_GENERATED_MANIFEST("The manifest was created using a using checksum utilities such as those\n" + - "contained in the GNU Coreutils package (md5sum, sha1sum, etc.), collectively referred to here as 'md5sum'. " - + "This creates slight differences in generated manifests that can cause problems in some implementations."), - MISSING_TAG_MANIEST("The tag manifest guards against a truncated payload manifest as well as other potental " - + "problems and is always recommened that it be included."), - OLD_BAGIT_VERSION("The bagit specification version is not the newest. Consider converting to the latest version."), - OS_SPECIFIC_FILES("Files created by the operating system (OS) for its own use. They are non-portable across OS versions " - + "and should not be included in any manifest. Examples Thumbs.db on Windows or .DS_Store on OS X"), - PAYLOAD_OXUM_MISSING("It is recommended to always include the Payload-Oxum in the bag metadata " - + "since it allows for a 'quick verification' of the bag."), - TAG_FILES_ENCODING("It is recommended to always use UTF-8"), - WEAK_CHECKSUM_ALGORITHM("The checksum algorithm used is known to be weak. We recommend using SHA512 at a minium"); + BAG_WITHIN_A_BAG("bag_within_a_bag"), + DIFFERENT_CASE("different_case"), + DIFFERENT_NORMALIZATION("different_normalization"), + EXTRA_LINES_IN_BAGIT_FILES("extra_lines_in_bagit_files"), + LEADING_DOT_SLASH("leading_dot_slash"), + NON_STANDARD_ALGORITHM("non_standard_algorithm"), + MD5SUM_TOOL_GENERATED_MANIFEST("md5sum_tool_generated_manifest"), + MISSING_TAG_MANIFEST("missing_tag_manifest"), + OLD_BAGIT_VERSION("old_bagit_version"), + OS_SPECIFIC_FILES("os_specific_files"), + PAYLOAD_OXUM_MISSING("payload_oxum_missing"), + TAG_FILES_ENCODING("tag_files_encoding"), + WEAK_CHECKSUM_ALGORITHM("weak_checksum_algorithm"); - private final String reason; + private final String messageBundleKey; + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagitWarning(final String reason){ - this.reason = reason; + this.messageBundleKey = reason; } public String getReason() { - return reason; + return messages.getString(messageBundleKey); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/EncodingChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/EncodingChecker.java index f5b143cb1..b878ad6d0 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/EncodingChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/EncodingChecker.java @@ -3,6 +3,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -14,13 +15,14 @@ */ public interface EncodingChecker { Logger logger = LoggerFactory.getLogger(EncodingChecker.class); + ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); /* * It is now normal for all files to be UTF-8 */ static void checkEncoding(final Charset encoding, final Set warnings, final Collection warningsToIgnore){ if(!warningsToIgnore.contains(BagitWarning.TAG_FILES_ENCODING) && !StandardCharsets.UTF_8.equals(encoding)){ - logger.warn("Tag files are encoded with [{}]. We recommend always using UTF-8 instead.", encoding); + logger.warn(messages.getString("tag_files_not_encoded_with_utf8_warning"), encoding); warnings.add(BagitWarning.TAG_FILES_ENCODING); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java index db77277c8..ee0310750 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java @@ -9,10 +9,12 @@ import java.text.Normalizer; import java.util.Collection; import java.util.HashSet; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.exceptions.InvalidBagitFileFormatException; import gov.loc.repository.bagit.util.PathUtils; @@ -24,6 +26,7 @@ @SuppressWarnings({"PMD.UseLocaleWithCaseConversions"}) public final class ManifestChecker { private static final Logger logger = LoggerFactory.getLogger(ManifestChecker.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private static final String THUMBS_DB_FILE = "[Tt][Hh][Uu][Mm][Bb][Ss]\\.[Dd][Bb]"; private static final String DS_STORE_FILE = "\\.[Dd][Ss]_[Ss][Tt][Oo][Rr][Ee]"; @@ -61,9 +64,9 @@ public static void checkManifests(final Path bagitDir, final Charset encoding, f } } - if(!warningsToIgnore.contains(BagitWarning.MISSING_TAG_MANIEST) && missingTagManifest){ - logger.warn("Bag [{}] does not contain a tag manifest, which is always recommended.", bagitDir); - warnings.add(BagitWarning.MISSING_TAG_MANIEST); + if(!warningsToIgnore.contains(BagitWarning.MISSING_TAG_MANIFEST) && missingTagManifest){ + logger.warn(messages.getString("bag_missing_tag_manifest_warning"), bagitDir); + warnings.add(BagitWarning.MISSING_TAG_MANIFEST); } } @@ -81,7 +84,7 @@ private static void checkData(final Path manifestFile, final Charset encoding, f path = checkForManifestCreatedWithMD5SumTools(path, warnings, warningsToIgnore); if(!warningsToIgnore.contains(BagitWarning.DIFFERENT_CASE) && paths.contains(path.toLowerCase())){ - logger.warn("In manifest [{}], path [{}] is the same as another path except for the case. This can cause problems if moving the bag to a filesystem that is case insensitive.", manifestFile, path); + logger.warn(messages.getString("different_case_warning"), manifestFile, path); warnings.add(BagitWarning.DIFFERENT_CASE); } paths.add(path.toLowerCase()); @@ -104,7 +107,8 @@ private static void checkData(final Path manifestFile, final Charset encoding, f static String parsePath(final String line) throws InvalidBagitFileFormatException{ final String[] parts = line.split("\\s+", 2); if(parts.length < 2){ - throw new InvalidBagitFileFormatException("Manifest contains line [" + line + "] which does not follow the specified form of "); + final String formattedMessage = messages.getString("manifest_line_violated_spec_error"); + throw new InvalidBagitFileFormatException(MessageFormatter.format(formattedMessage, line).getMessage()); } return parts[1]; @@ -119,8 +123,7 @@ private static String checkForManifestCreatedWithMD5SumTools(final String path, } if(!warningsToIgnore.contains(BagitWarning.MD5SUM_TOOL_GENERATED_MANIFEST) && startsWithStar){ - logger.warn("Path [{}] starts with a *, which means it was generated with a non-bagit tool. " - + "It is recommended to remove the * in order to conform to the bagit specification.", path); + logger.warn(messages.getString("md5sum_generated_line_warning"), path); warnings.add(BagitWarning.MD5SUM_TOOL_GENERATED_MANIFEST); } @@ -135,7 +138,10 @@ private static void checkNormalization(final String path, final Path rootDir, fi final Path fileToCheck = rootDir.resolve(path).normalize(); final Path dirToCheck = fileToCheck.getParent(); - if(dirToCheck == null){ throw new IOException("Could not access parent folder of " + fileToCheck);} //to satisfy findbugs + if(dirToCheck == null){ + final String formattedMessage = messages.getString("cannot_access_parent_path_error"); + throw new IOException(MessageFormatter.format(formattedMessage, fileToCheck).getMessage()); //to satisfy findbugs + } final String normalizedFileToCheck = normalizePathToNFD(fileToCheck); try(final DirectoryStream files = Files.newDirectoryStream(dirToCheck)){ @@ -143,7 +149,7 @@ private static void checkNormalization(final String path, final Path rootDir, fi final String normalizedFile = normalizePathToNFD(file); if(!file.equals(fileToCheck) && normalizedFileToCheck.equals(normalizedFile)){ - logger.warn("File [{}] has a different normalization then what is specified in the manifest.", fileToCheck); + logger.warn(messages.getString("different_normalization_warning"), fileToCheck); warnings.add(BagitWarning.DIFFERENT_NORMALIZATION); } } @@ -163,7 +169,7 @@ static String normalizePathToNFD(final Path path){ */ private static void checkForBagWithinBag(final String line, final Set warnings, final Collection warningsToIgnore, final boolean isPayloadManifest){ if(!warningsToIgnore.contains(BagitWarning.BAG_WITHIN_A_BAG) && isPayloadManifest && line.contains("manifest-")){ - logger.warn("We stronger recommend not storing a bag within a bag as it is known to cause problems."); + logger.warn(messages.getString("bag_within_bag_warning")); warnings.add(BagitWarning.BAG_WITHIN_A_BAG); } } @@ -173,7 +179,7 @@ private static void checkForBagWithinBag(final String line, final Set warnings, final Collection warningsToIgnore, final Path manifestFile){ if(!warningsToIgnore.contains(BagitWarning.LEADING_DOT_SLASH) && line.contains("./")){ - logger.warn("In manifest [{}] line [{}] is a non-normalized path.", manifestFile, line); + logger.warn(messages.getString("leading_dot_slash_warning"), manifestFile, line); warnings.add(BagitWarning.LEADING_DOT_SLASH); } } @@ -183,7 +189,7 @@ private static void checkForRelativePaths(final String line, final Set warnings, final Collection warningsToIgnore, final Path manifestFile){ if(!warningsToIgnore.contains(BagitWarning.OS_SPECIFIC_FILES) && line.matches(OS_FILES_REGEX)){ - logger.warn("In manifest [{}] line [{}] contains a OS specific file.", manifestFile, line); + logger.warn(messages.getString("os_specific_files_warning"), manifestFile, line); warnings.add(BagitWarning.OS_SPECIFIC_FILES); } } @@ -195,14 +201,12 @@ static void checkAlgorthm(final String algorithm, final Set warnin final String upperCaseAlg = algorithm.toUpperCase(); if(!warningsToIgnore.contains(BagitWarning.WEAK_CHECKSUM_ALGORITHM) && (upperCaseAlg.startsWith("MD") || upperCaseAlg.matches("SHA(1|224|256|384)?"))){ - logger.warn("Detected a known weak algorithm [{}]. With the great advances in computer hardware there is little penalty " - + "to using more bits to calculate the checksum.", algorithm); + logger.warn(messages.getString("weak_algorithm_warning"), algorithm); warnings.add(BagitWarning.WEAK_CHECKSUM_ALGORITHM); } else if(!warningsToIgnore.contains(BagitWarning.NON_STANDARD_ALGORITHM) && !"SHA-512".equals(upperCaseAlg)){ - logger.warn("Detected algorithm [{}] which is not included by default in Java. This will make it more difficult " - + "to read this bag on some systems. Consider changing it to SHA-512.", algorithm); + logger.warn(messages.getString("non_standard_algorithm_warning"), algorithm); warnings.add(BagitWarning.NON_STANDARD_ALGORITHM); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/MetadataChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/MetadataChecker.java index 3238a4514..912287fb1 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/MetadataChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/MetadataChecker.java @@ -6,6 +6,7 @@ import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Collection; import java.util.List; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -20,6 +21,7 @@ */ public final class MetadataChecker { private static final Logger logger = LoggerFactory.getLogger(MetadataChecker.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private MetadataChecker(){ //intentionally left empty @@ -46,7 +48,7 @@ private static void checkForPayloadOxumMetadata(final Path bagitDir, final Chars } if(!containsPayloadOxum){ - logger.warn("The Payload-Oxum key was not found in the bag metadata. This will prevent a \"quick verify\"."); + logger.warn(messages.getString("missing_payload_oxum_warning")); warnings.add(BagitWarning.PAYLOAD_OXUM_MISSING); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/VersionChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/VersionChecker.java index 5efdebd4c..6da15e612 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/VersionChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/VersionChecker.java @@ -1,6 +1,7 @@ package gov.loc.repository.bagit.conformance; import java.util.Collection; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -15,13 +16,14 @@ public interface VersionChecker { Logger logger = LoggerFactory.getLogger(VersionChecker.class); Version LATEST_BAGIT_VERSION = new Version(0, 97); + ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); /* * Check that they are using the latest version */ static void checkVersion(final Version version, final Set warnings, final Collection warningsToIgnore){ if(!warningsToIgnore.contains(BagitWarning.OLD_BAGIT_VERSION) && version.isOlder(LATEST_BAGIT_VERSION)){ - logger.warn("Found version [{}] of the bagit specification but the latest version is [{}].", version, LATEST_BAGIT_VERSION); + logger.warn(messages.getString("old_version_warning"), version, LATEST_BAGIT_VERSION); warnings.add(BagitWarning.OLD_BAGIT_VERSION); } } diff --git a/src/main/java/gov/loc/repository/bagit/conformance/profile/BagitProfileDeserializer.java b/src/main/java/gov/loc/repository/bagit/conformance/profile/BagitProfileDeserializer.java index 47a6cffe1..4684d02bc 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/profile/BagitProfileDeserializer.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/profile/BagitProfileDeserializer.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,6 +24,7 @@ public class BagitProfileDeserializer extends StdDeserializer { private static final long serialVersionUID = 1L; private static final Logger logger = LoggerFactory.getLogger(BagitProfileDeserializer.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); public BagitProfileDeserializer() { this(null); @@ -45,10 +47,10 @@ public BagitProfile deserialize(final JsonParser p, final DeserializationContext profile.getManifestTypesRequired().addAll(parseManifestTypesRequired(node)); profile.setFetchFileAllowed(node.get("Allow-Fetch.txt").asBoolean()); - logger.debug("Are fetch files allowed? {}", profile.isFetchFileAllowed()); + logger.debug(messages.getString("fetch_allowed"), profile.isFetchFileAllowed()); profile.setSerialization(Serialization.valueOf(node.get("Serialization").asText())); - logger.debug("Serialization allowed [{}]",profile.getSerialization()); + logger.debug(messages.getString("serialization_allowed"),profile.getSerialization()); profile.getAcceptableMIMESerializationTypes().addAll(parseAcceptableSerializationFormats(node)); @@ -63,37 +65,37 @@ public BagitProfile deserialize(final JsonParser p, final DeserializationContext private static void parseBagitProfileInfo(final JsonNode node, final BagitProfile profile){ final JsonNode bagitProfileInfoNode = node.get("BagIt-Profile-Info"); - logger.debug("Parsing the BagIt-Profile-Info section"); + logger.debug(messages.getString("parsing_bagit_profile_info_section")); final String profileIdentifier = bagitProfileInfoNode.get("BagIt-Profile-Identifier").asText(); - logger.debug("Identifier is [{}]", profileIdentifier); + logger.debug(messages.getString("identifier"), profileIdentifier); profile.setBagitProfileIdentifier(profileIdentifier); final String sourceOrg = bagitProfileInfoNode.get("Source-Organization").asText(); - logger.debug("Source-Organization is [{}]", sourceOrg); + logger.debug(messages.getString("source_organization"), sourceOrg); profile.setSourceOrganization(sourceOrg); final String contactName = bagitProfileInfoNode.get("Contact-Name").asText(); - logger.debug("Contact-Name is [{}]", contactName); + logger.debug(messages.getString("contact_name"), contactName); profile.setContactName(contactName); final String contactEmail = bagitProfileInfoNode.get("Contact-Email").asText(); - logger.debug("Contact-Email is [{}]", contactEmail); + logger.debug(messages.getString("contact_email"), contactEmail); profile.setContactEmail(contactEmail); final String extDescript = bagitProfileInfoNode.get("External-Description").asText(); - logger.debug("External-Description is [{}]", extDescript); + logger.debug(messages.getString("external_description"), extDescript); profile.setExternalDescription(extDescript); final String version = bagitProfileInfoNode.get("Version").asText(); - logger.debug("Version is [{}]", version); + logger.debug(messages.getString("version"), version); profile.setVersion(version); } @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private static Map parseBagInfo(final JsonNode rootNode){ final JsonNode bagInfoNode = rootNode.get("Bag-Info"); - logger.debug("Parsing the Bag-Info section"); + logger.debug(messages.getString("parsing_bag_info")); final Map bagInfo = new HashMap<>(); final Iterator> nodes = bagInfoNode.fields(); //stuck in java 6... @@ -127,7 +129,7 @@ private static List parseManifestTypesRequired(final JsonNode node){ manifestTypes.add(manifestName.asText()); } - logger.debug("Required manifest types {}", manifestTypes); + logger.debug(messages.getString("required_manifest_types"), manifestTypes); return manifestTypes; } @@ -139,7 +141,7 @@ private static List parseAcceptableSerializationFormats(final JsonNode n for (final JsonNode serialiationFormat : serialiationFormats) { serialTypes.add(serialiationFormat.asText()); } - logger.debug("Acceptable serialization MIME types are {}", serialTypes); + logger.debug(messages.getString("acceptable_serialization_mime_types"), serialTypes); return serialTypes; } @@ -151,7 +153,7 @@ private static List parseRequiredTagmanifestTypes(final JsonNode node){ for(final JsonNode tagManifestsRequiredNode : tagManifestsRequiredNodes){ requiredTagmanifestTypes.add(tagManifestsRequiredNode.asText()); } - logger.debug("Required Tagmanifest types are {}", requiredTagmanifestTypes); + logger.debug(messages.getString("required_tagmanifest_types"), requiredTagmanifestTypes); return requiredTagmanifestTypes; } @@ -163,7 +165,7 @@ private static List parseRequiredTagFiles(final JsonNode node){ for(final JsonNode tagFilesRequiredNode : tagFilesRequiredNodes){ requiredTagFiles.add(tagFilesRequiredNode.asText()); } - logger.debug("Tag files required are {}", requiredTagFiles); + logger.debug(messages.getString("tag_files_required"), requiredTagFiles); return requiredTagFiles; } @@ -175,7 +177,7 @@ private static List parseAcceptableVersions(final JsonNode node){ for(final JsonNode acceptableVersionsNode : acceptableVersionsNodes){ acceptableVersions.add(acceptableVersionsNode.asText()); } - logger.debug("Acceptable bagit versions are {}", acceptableVersions); + logger.debug(messages.getString("acceptable_bagit_versions"), acceptableVersions); return acceptableVersions; } diff --git a/src/main/java/gov/loc/repository/bagit/creator/AbstractCreateManifestsVistor.java b/src/main/java/gov/loc/repository/bagit/creator/AbstractCreateManifestsVistor.java index c808d2be0..d29c455cd 100644 --- a/src/main/java/gov/loc/repository/bagit/creator/AbstractCreateManifestsVistor.java +++ b/src/main/java/gov/loc/repository/bagit/creator/AbstractCreateManifestsVistor.java @@ -9,6 +9,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; import java.util.Map; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,6 +24,7 @@ */ public abstract class AbstractCreateManifestsVistor extends SimpleFileVisitor{ private static final Logger logger = LoggerFactory.getLogger(AbstractCreateManifestsVistor.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); protected final Map manifestToMessageDigestMap; protected final boolean includeHiddenFiles; @@ -34,11 +36,11 @@ public AbstractCreateManifestsVistor(final Map manifest public FileVisitResult abstractPreVisitDirectory(final Path dir, final String directoryToIgnore) throws IOException { if(!includeHiddenFiles && PathUtils.isHidden(dir) && !dir.endsWith(Paths.get(".bagit"))){ - logger.debug("Skipping [{}] since we are ignoring hidden files", dir); + logger.debug(messages.getString("skipping_hidden_file"), dir); return FileVisitResult.SKIP_SUBTREE; } if(dir.endsWith(directoryToIgnore)){ - logger.debug("Skipping {} directory cause it shouldn't be in the manifest", dir); + logger.debug(messages.getString("skipping_ignored_directory"), dir); return FileVisitResult.SKIP_SUBTREE; } @@ -48,7 +50,7 @@ public FileVisitResult abstractPreVisitDirectory(final Path dir, final String di @Override 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); + logger.debug(messages.getString("skipping_hidden_file"), path); } else{ Hasher.hash(path, manifestToMessageDigestMap); 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 8db151838..082ac8e9f 100644 --- a/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java +++ b/src/main/java/gov/loc/repository/bagit/creator/BagCreator.java @@ -8,6 +8,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Collection; import java.util.Map; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,9 +27,11 @@ */ public final class BagCreator { private static final Logger logger = LoggerFactory.getLogger(BagCreator.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagCreator(){} + @SuppressWarnings("CPD-START") /** * 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 @@ -44,7 +47,7 @@ private BagCreator(){} public static Bag bagInPlace(final Path root, final Collection algorithms, 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); + logger.info(messages.getString("creating_bag"), bag.getVersion(), root); final Path dataDir = root.resolve("data"); Files.createDirectory(dataDir); @@ -56,7 +59,7 @@ public static Bag bagInPlace(final Path root, final Collection payloadFilesMap = Hasher.createManifestToMessageDigestMap(algorithms); final CreatePayloadManifestsVistor payloadVisitor = new CreatePayloadManifestsVistor(payloadFilesMap, includeHidden); Files.walkFileTree(dataDir, payloadVisitor); @@ -65,7 +68,7 @@ public static Bag bagInPlace(final Path root, final Collection tagFilesMap = Hasher.createManifestToMessageDigestMap(algorithms); final CreateTagManifestsVistor tagVistor = new CreateTagManifestsVistor(tagFilesMap, includeHidden); Files.walkFileTree(root, tagVistor); @@ -76,6 +79,7 @@ public static Bag bagInPlace(final Path root, final Collection algorithms, final boolean includeHidden) throws NoSuchAlgorithmException, IOException{ final Bag bag = new Bag(new Version(2, 0)); bag.setRootDir(root); - logger.info("Creating a bag with version: [{}] in directory: [{}]", bag.getVersion(), root); + logger.info(messages.getString("creating_bag"), bag.getVersion(), root); final Path dotbagitDir = root.resolve(".bagit"); Files.createDirectories(dotbagitDir); - logger.info("Creating payload manifest"); + logger.info(messages.getString("creating_payload_manifests")); final Map map = Hasher.createManifestToMessageDigestMap(algorithms); final CreatePayloadManifestsVistor visitor = new CreatePayloadManifestsVistor(map, includeHidden); Files.walkFileTree(root, visitor); @@ -106,7 +110,7 @@ public static Bag createDotBagit(final Path root, final Collection tagFilesMap = Hasher.createManifestToMessageDigestMap(algorithms); final CreateTagManifestsVistor tagVistor = new CreateTagManifestsVistor(tagFilesMap, includeHidden); Files.walkFileTree(dotbagitDir, tagVistor); @@ -116,4 +120,5 @@ public static Bag createDotBagit(final Path root, final Collection acceptableVersions) { + super(MessageFormatter.format(message, version, acceptableVersions).getMessage()); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/FetchFileNotAllowedException.java b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/FetchFileNotAllowedException.java index 4b25ef4e2..734a2c0c0 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/FetchFileNotAllowedException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/FetchFileNotAllowedException.java @@ -1,12 +1,16 @@ package gov.loc.repository.bagit.exceptions.conformance; +import java.nio.file.Path; + +import org.slf4j.helpers.MessageFormatter; + /** * Class to represent when a fetch file is found in a bag but is not allowed according to the bagit profile */ public class FetchFileNotAllowedException extends Exception { private static final long serialVersionUID = 1L; - public FetchFileNotAllowedException(final String message) { - super(message); + public FetchFileNotAllowedException(final String message, final Path rootDir) { + super(MessageFormatter.format(message, rootDir).getMessage()); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/MetatdataValueIsNotAcceptableException.java b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/MetatdataValueIsNotAcceptableException.java index 66884dd6c..7989db7c6 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/MetatdataValueIsNotAcceptableException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/MetatdataValueIsNotAcceptableException.java @@ -1,12 +1,16 @@ package gov.loc.repository.bagit.exceptions.conformance; +import java.util.List; + +import org.slf4j.helpers.MessageFormatter; + /** * Class to represent when a metadata's value is not in the acceptable list of values */ public class MetatdataValueIsNotAcceptableException extends Exception { private static final long serialVersionUID = 1L; - public MetatdataValueIsNotAcceptableException(final String message) { - super(message); + public MetatdataValueIsNotAcceptableException(final String message, final String metadataKey, final List acceptableValues, final String actualValue) { + super(MessageFormatter.arrayFormat(message, new Object[]{metadataKey, acceptableValues, actualValue}).getMessage()); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredMetadataFieldNotPresentException.java b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredMetadataFieldNotPresentException.java index 8bc3407db..8af60d064 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredMetadataFieldNotPresentException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredMetadataFieldNotPresentException.java @@ -1,12 +1,14 @@ package gov.loc.repository.bagit.exceptions.conformance; +import org.slf4j.helpers.MessageFormatter; + /** * Class to represent when a specific metadata field is not found */ public class RequiredMetadataFieldNotPresentException extends Exception { private static final long serialVersionUID = 1L; - public RequiredMetadataFieldNotPresentException(final String message) { - super(message); + public RequiredMetadataFieldNotPresentException(final String message, final String bagInfoEntryRequirementKey) { + super(MessageFormatter.format(message, bagInfoEntryRequirementKey).getMessage()); } } diff --git a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredTagFileNotPresentException.java b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredTagFileNotPresentException.java index 313edfe52..5bbc93d53 100644 --- a/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredTagFileNotPresentException.java +++ b/src/main/java/gov/loc/repository/bagit/exceptions/conformance/RequiredTagFileNotPresentException.java @@ -1,12 +1,14 @@ package gov.loc.repository.bagit.exceptions.conformance; +import org.slf4j.helpers.MessageFormatter; + /** * Class to represent when a specific tag file is not found */ public class RequiredTagFileNotPresentException extends Exception { private static final long serialVersionUID = 1L; - public RequiredTagFileNotPresentException(final String message) { - super(message); + public RequiredTagFileNotPresentException(final String message, final String requiredTagFilePath) { + super(MessageFormatter.format(message, requiredTagFilePath).getMessage()); } } 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 c49eac524..55816ac52 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/Hasher.java +++ b/src/main/java/gov/loc/repository/bagit/hash/Hasher.java @@ -13,6 +13,7 @@ import java.util.Formatter; import java.util.HashMap; import java.util.Map; +import java.util.ResourceBundle; import java.util.Map.Entry; import org.slf4j.Logger; @@ -27,6 +28,7 @@ public final class Hasher { private static final Logger logger = LoggerFactory.getLogger(Hasher.class); private static final int _64_KB = 1024 * 64; private static final int CHUNK_SIZE = _64_KB; + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private Hasher(){ //intentionally left empty @@ -75,7 +77,7 @@ static void updateMessageDigests(final Path path, final Collection manifestToMessageDigestMap){ for(final Entry entry : manifestToMessageDigestMap.entrySet()){ final String hash = formatMessageDigest(entry.getValue()); - logger.debug("Adding [{}] to manifest with hash [{}]", path, hash); + logger.debug(messages.getString("adding_checksum"), path, hash); entry.getKey().getFileToChecksumMap().put(path, 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 b06483ca9..d35e71cb2 100644 --- a/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java +++ b/src/main/java/gov/loc/repository/bagit/hash/StandardBagitAlgorithmNameToSupportedAlgorithmMapping.java @@ -1,6 +1,7 @@ package gov.loc.repository.bagit.hash; import java.util.Locale; +import java.util.ResourceBundle; import gov.loc.repository.bagit.exceptions.UnsupportedAlgorithmException; @@ -9,6 +10,7 @@ */ public class StandardBagitAlgorithmNameToSupportedAlgorithmMapping implements BagitAlgorithmNameToSupportedAlgorithmMapping { + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); @Override public SupportedAlgorithm getSupportedAlgorithm(final String bagitAlgorithmName) throws UnsupportedAlgorithmException { @@ -16,7 +18,7 @@ public SupportedAlgorithm getSupportedAlgorithm(final String bagitAlgorithmName) return StandardSupportedAlgorithms.valueOf(bagitAlgorithmName.toUpperCase(Locale.getDefault())); } catch(IllegalArgumentException e){ - throw new UnsupportedAlgorithmException(bagitAlgorithmName + " is not supported!", e); + throw new UnsupportedAlgorithmException(messages.getString("algorithm_not_supported_error"), bagitAlgorithmName, e); } } } diff --git a/src/main/java/gov/loc/repository/bagit/reader/BagitTextFileReader.java b/src/main/java/gov/loc/repository/bagit/reader/BagitTextFileReader.java index a31a7e60b..766e0f023 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/BagitTextFileReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/BagitTextFileReader.java @@ -6,11 +6,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.ResourceBundle; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.domain.Version; import gov.loc.repository.bagit.exceptions.InvalidBagMetadataException; @@ -23,6 +25,7 @@ public final class BagitTextFileReader { private static final Logger logger = LoggerFactory.getLogger(BagitTextFileReader.class); private static final byte[] BOM = new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF}; + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagitTextFileReader(){ //intentionally left empty @@ -40,7 +43,7 @@ private BagitTextFileReader(){ * @throws InvalidBagitFileFormatException if the bagit.txt file does not conform to the bagit spec */ public static SimpleImmutableEntry readBagitTextFile(final Path bagitFile) throws IOException, UnparsableVersionException, InvalidBagMetadataException, InvalidBagitFileFormatException{ - logger.debug("Reading [{}] for version and encoding", bagitFile); + logger.debug(messages.getString("reading_version_and_encoding"), bagitFile); throwErrorIfByteOrderMarkIsPresent(bagitFile); final List> pairs = KeyValueReader.readKeyValuesFromFile(bagitFile, ":", StandardCharsets.UTF_8); @@ -49,16 +52,16 @@ public static SimpleImmutableEntry readBagitTextFile(final Pat for(final SimpleImmutableEntry pair : pairs){ if("BagIt-Version".equals(pair.getKey())){ version = pair.getValue(); - logger.debug("BagIt-Version is [{}]", version); + logger.debug(messages.getString("bagit_version"), version); } if("Tag-File-Character-Encoding".equals(pair.getKey())){ encoding = Charset.forName(pair.getValue()); - logger.debug("Tag-File-Character-Encoding is [{}]", encoding); + logger.debug(messages.getString("tag_file_encoding"), encoding); } } if(version == null || encoding == null){ - throw new InvalidBagitFileFormatException("bagit.txt MUST contain 'BagIt-Version' AND 'Tag-File-Character-Encoding' entries!"); + throw new InvalidBagitFileFormatException(messages.getString("invalid_bagit_text_file_error")); } return new SimpleImmutableEntry<>(parseVersion(version), encoding); @@ -70,8 +73,8 @@ public static SimpleImmutableEntry readBagitTextFile(final Pat private static void throwErrorIfByteOrderMarkIsPresent(final Path bagitFile) throws IOException, InvalidBagitFileFormatException{ final byte[] firstFewBytesInFile = Arrays.copyOfRange(Files.readAllBytes(bagitFile), 0, BOM.length); if(Arrays.equals(BOM, firstFewBytesInFile)){ - throw new InvalidBagitFileFormatException("File [" + bagitFile + "] contains a byte order mark (BOM) which " - + "is not allowed by the bagit specification!"); + final String formattedMessage = messages.getString("bom_present_error"); + throw new InvalidBagitFileFormatException(MessageFormatter.format(formattedMessage, bagitFile).getMessage()); } } @@ -80,7 +83,7 @@ private static void throwErrorIfByteOrderMarkIsPresent(final Path bagitFile) thr */ public static Version parseVersion(final String version) throws UnparsableVersionException{ if(!version.contains(".")){ - throw new UnparsableVersionException("Version must be in format MAJOR.MINOR but was " + version); + throw new UnparsableVersionException(messages.getString("unparsable_version_error"), version); } final String[] parts = version.split("\\."); diff --git a/src/main/java/gov/loc/repository/bagit/reader/FetchReader.java b/src/main/java/gov/loc/repository/bagit/reader/FetchReader.java index 69f0197b8..594883b9e 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/FetchReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/FetchReader.java @@ -8,6 +8,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,6 +22,7 @@ */ public final class FetchReader { private static final Logger logger = LoggerFactory.getLogger(FetchReader.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private FetchReader(){ //intentionally left empty @@ -40,7 +42,7 @@ private FetchReader(){ */ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public static List readFetch(final Path fetchFile, final Charset encoding, final Path bagRootDir) throws IOException, MaliciousPathException, InvalidBagitFileFormatException{ - logger.info("Attempting to read [{}]", fetchFile); + logger.info(messages.getString("reading_fetch_file"), fetchFile); final List itemsToFetch = new ArrayList<>(); try(final BufferedReader reader = Files.newBufferedReader(fetchFile, encoding)){ @@ -54,7 +56,7 @@ public static List readFetch(final Path fetchFile, final Charset enco 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); + logger.debug(messages.getString("read_fetch_file_line"), url, length, parts[2], fetchFile); final FetchItem itemToFetch = new FetchItem(url, length, path); itemsToFetch.add(itemToFetch); diff --git a/src/main/java/gov/loc/repository/bagit/reader/KeyValueReader.java b/src/main/java/gov/loc/repository/bagit/reader/KeyValueReader.java index 3571cbf69..c0413b2f8 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/KeyValueReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/KeyValueReader.java @@ -8,9 +8,11 @@ import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.List; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.exceptions.InvalidBagMetadataException; @@ -19,6 +21,8 @@ */ public final class KeyValueReader { private static final Logger logger = LoggerFactory.getLogger(KeyValueReader.class); + private static final String INDENTED_LINE_REGEX = "^\\s+.*"; + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private KeyValueReader(){ //intentionall left blank @@ -44,14 +48,14 @@ public static List> readKeyValuesFromFile(f try(final BufferedReader reader = Files.newBufferedReader(file, charset)){ String line = reader.readLine(); while(line != null){ - if(line.matches("^\\s+.*") && !keyValues.isEmpty()){ + if(line.matches(INDENTED_LINE_REGEX) && !keyValues.isEmpty()){ mergeIndentedLine(line, keyValues); } else{ final String[] parts = checkLineFormat(line, splitRegex); final String key = parts[0].trim(); final String value = parts[1].trim(); - logger.debug("Found key [{}] value [{}] in file [{}] using split regex [{}]", key, value, file, splitRegex); + logger.debug(messages.getString("read_key_value_line"), key, value, file, splitRegex); keyValues.add(new SimpleImmutableEntry<>(key, value)); } @@ -67,22 +71,15 @@ private static void mergeIndentedLine(final String line, final List newKeyValue = new SimpleImmutableEntry<>(oldKeyValue.getKey(), oldKeyValue.getValue() + System.lineSeparator() +line); keyValues.add(newKeyValue); - logger.debug("Found an indented line - merging it with key [{}]", oldKeyValue.getKey()); + logger.debug(messages.getString("found_indented_line"), oldKeyValue.getKey()); } private static String[] checkLineFormat(final String line, final String splitRegex) throws InvalidBagMetadataException{ final String[] parts = line.split(splitRegex, 2); if(parts.length != 2){ - 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 ") - .append(splitRegex) - .append(" or if continuing from another line must be indented by a space or a tab."); - - throw new InvalidBagMetadataException(message.toString()); + final String formattedMessage = messages.getString("malformed_key_value_line_error"); + throw new InvalidBagMetadataException(MessageFormatter.format(formattedMessage, line, splitRegex).getMessage()); } return parts; diff --git a/src/main/java/gov/loc/repository/bagit/reader/ManifestReader.java b/src/main/java/gov/loc/repository/bagit/reader/ManifestReader.java index b4fbe30d8..fc0b86117 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/ManifestReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/ManifestReader.java @@ -9,6 +9,7 @@ import java.security.MessageDigest; import java.util.HashMap; import java.util.Map; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +28,7 @@ */ public final class ManifestReader { private static final Logger logger = LoggerFactory.getLogger(ManifestReader.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private ManifestReader(){ //intentionally left empty @@ -46,18 +48,18 @@ private ManifestReader(){ * @throws InvalidBagitFileFormatException if the manifest is not formatted properly */ static void readAllManifests(final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping, final Path rootDir, final Bag bag) throws IOException, MaliciousPathException, UnsupportedAlgorithmException, InvalidBagitFileFormatException{ - logger.info("Attempting to find and read manifests"); + logger.info(messages.getString("attempting_read_manifests")); try(final DirectoryStream manifests = getAllManifestFiles(rootDir)){ for (final Path path : manifests){ final String filename = PathUtils.getFilename(path); if(filename.startsWith("tagmanifest-")){ - logger.debug("Found tag manifest [{}]", path); + logger.debug(messages.getString("found_tagmanifest"), path); bag.getTagManifests().add(readManifest(nameMapping, path, bag.getRootDir(), bag.getFileEncoding())); } else if(filename.startsWith("manifest-")){ - logger.debug("Found payload manifest [{}]", path); + logger.debug(messages.getString("found_payload_manifest"), path); bag.getPayLoadManifests().add(readManifest(nameMapping, path, bag.getRootDir(), bag.getFileEncoding())); } } @@ -97,7 +99,7 @@ public boolean accept(final Path file) throws IOException { public static Manifest readManifest(final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping, final Path manifestFile, final Path bagRootDir, final Charset charset) throws IOException, MaliciousPathException, UnsupportedAlgorithmException, InvalidBagitFileFormatException{ - logger.debug("Reading manifest [{}]", manifestFile); + logger.debug(messages.getString("reading_manifest"), manifestFile); final String alg = PathUtils.getFilename(manifestFile).split("[-\\.]")[1]; final SupportedAlgorithm algorithm = nameMapping.getSupportedAlgorithm(alg); diff --git a/src/main/java/gov/loc/repository/bagit/reader/MetadataReader.java b/src/main/java/gov/loc/repository/bagit/reader/MetadataReader.java index 55e99bdef..adb9f9451 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/MetadataReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/MetadataReader.java @@ -7,6 +7,7 @@ import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.List; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,6 +19,7 @@ */ public final class MetadataReader { private static final Logger logger = LoggerFactory.getLogger(MetadataReader.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private MetadataReader(){ //intentionally left empty @@ -34,17 +36,17 @@ private MetadataReader(){ * @throws InvalidBagMetadataException if the metadata file does not conform to the bagit spec */ public static List> readBagMetadata(final Path rootDir, final Charset encoding) throws IOException, InvalidBagMetadataException{ - logger.info("Attempting to read bag metadata file"); + logger.info(messages.getString("attempting_read_metadata")); List> metadata = new ArrayList<>(); final Path bagInfoFile = rootDir.resolve("bag-info.txt"); if(Files.exists(bagInfoFile)){ - logger.debug("Found [{}] file", bagInfoFile); + logger.debug(messages.getString("found_metadata_file"), bagInfoFile); metadata = KeyValueReader.readKeyValuesFromFile(bagInfoFile, ":", encoding); } 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); + logger.debug(messages.getString("found_metadata_file"), packageInfoFile); metadata = KeyValueReader.readKeyValuesFromFile(packageInfoFile, ":", encoding); } diff --git a/src/main/java/gov/loc/repository/bagit/reader/TagFileReader.java b/src/main/java/gov/loc/repository/bagit/reader/TagFileReader.java index ec8313fbe..d2fceda39 100644 --- a/src/main/java/gov/loc/repository/bagit/reader/TagFileReader.java +++ b/src/main/java/gov/loc/repository/bagit/reader/TagFileReader.java @@ -4,9 +4,11 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.exceptions.InvalidBagitFileFormatException; import gov.loc.repository.bagit.exceptions.MaliciousPathException; @@ -17,6 +19,7 @@ */ public interface TagFileReader { Logger logger = LoggerFactory.getLogger(TagFileReader.class); + ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); String ERROR_PREFIX = "Path ["; /* @@ -25,16 +28,18 @@ public interface TagFileReader { static Path createFileFromManifest(final Path bagRootDir, final String path) throws MaliciousPathException, InvalidBagitFileFormatException{ String fixedPath = path; if(path.charAt(0) == '*'){ - logger.warn("Encountered path that was created by non-bagit tool. Removing * from path. Please remove all * from manifest files!"); + logger.warn(messages.getString("removing_asterisk")); fixedPath = path.substring(1); //remove the * from the path } if(path.contains("\\")){ - throw new InvalidBagitFileFormatException(ERROR_PREFIX + path + "] is invalid due to the use of the path separactor [\\]"); + final String formattedMessage = messages.getString("blackslash_used_as_path_separator_error"); + throw new InvalidBagitFileFormatException(MessageFormatter.format(formattedMessage, path).getMessage()); } if(path.contains("~/")){ - throw new MaliciousPathException(ERROR_PREFIX + path + "] is trying to be malicious and access a file outside the bag"); + final String formattedMessage = messages.getString("malicious_path_error"); + throw new MaliciousPathException(MessageFormatter.format(formattedMessage, path).getMessage()); } fixedPath = PathUtils.decodeFilname(fixedPath); @@ -43,7 +48,8 @@ static Path createFileFromManifest(final Path bagRootDir, final String path) thr try { file = Paths.get(new URI(fixedPath)); } catch (URISyntaxException e) { - throw new InvalidBagitFileFormatException("URL [" + path + "] is invalid.", e); + final String formattedMessage = messages.getString("invalid_url_format_error"); + throw new InvalidBagitFileFormatException(MessageFormatter.format(formattedMessage, path).getMessage(), e); } } else{ @@ -51,8 +57,8 @@ static Path createFileFromManifest(final Path bagRootDir, final String path) thr } if(!file.normalize().startsWith(bagRootDir)){ - throw new MaliciousPathException(ERROR_PREFIX + file + "] is outside the bag root directory of " + bagRootDir + - "! This is not allowed according to the bagit specification!"); + final String formattedMessage = messages.getString("malicious_path_error"); + throw new MaliciousPathException(MessageFormatter.format(formattedMessage, file).getMessage()); } return file; diff --git a/src/main/java/gov/loc/repository/bagit/verify/AbstractPayloadFileExistsInManifestsVistor.java b/src/main/java/gov/loc/repository/bagit/verify/AbstractPayloadFileExistsInManifestsVistor.java index 3601a3984..ef413c910 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/AbstractPayloadFileExistsInManifestsVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/AbstractPayloadFileExistsInManifestsVistor.java @@ -7,6 +7,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +17,8 @@ */ abstract public class AbstractPayloadFileExistsInManifestsVistor extends SimpleFileVisitor { protected static final Logger logger = LoggerFactory.getLogger(AbstractPayloadFileExistsInManifestsVistor.class); - protected transient final boolean ignoreHiddenFiles; + protected static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); + protected final boolean ignoreHiddenFiles; public AbstractPayloadFileExistsInManifestsVistor(final boolean ignoreHiddenFiles) { this.ignoreHiddenFiles = ignoreHiddenFiles; @@ -25,10 +27,14 @@ public AbstractPayloadFileExistsInManifestsVistor(final boolean ignoreHiddenFile @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if(ignoreHiddenFiles && Files.isHidden(dir) || dir.endsWith(Paths.get(".bagit"))){ - logger.debug("Skipping [{}] cause it is a hidden folder", dir); + logger.debug(messages.getString("skipping_hidden_file"), dir); return FileVisitResult.SKIP_SUBTREE; } return FileVisitResult.CONTINUE; } + + public boolean isIgnoreHiddenFiles() { + return ignoreHiddenFiles; + } } 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 593a6cd4e..ce9eae49b 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java +++ b/src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java @@ -4,6 +4,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.ResourceBundle; import java.util.Map.Entry; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; @@ -33,6 +34,7 @@ */ public final class BagVerifier { private static final Logger logger = LoggerFactory.getLogger(BagVerifier.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private final PayloadVerifier manifestVerifier; private final ExecutorService executor; @@ -131,15 +133,15 @@ public static void quicklyVerify(final Bag bag) throws IOException, InvalidPaylo * @throws InvalidBagitFileFormatException if the manifest is not formatted properly */ public void isValid(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, MissingPayloadManifestException, MissingBagitFileException, MissingPayloadDirectoryException, FileNotInPayloadDirectoryException, InterruptedException, MaliciousPathException, CorruptChecksumException, VerificationException, UnsupportedAlgorithmException, InvalidBagitFileFormatException{ - logger.info("Checking if the bag with root directory [{}] is valid.", bag.getRootDir()); + logger.info(messages.getString("checking_bag_is_valid"), bag.getRootDir()); isComplete(bag, ignoreHiddenFiles); - logger.debug("Checking payload manifest(s) checksums"); + logger.debug(messages.getString("checking_payload_checksums")); for(final Manifest payloadManifest : bag.getPayLoadManifests()){ checkHashes(payloadManifest); } - logger.debug("Checking tag manifest(s) checksums"); + logger.debug(messages.getString("checking_tag_file_checksums")); for(final Manifest tagManifest : bag.getTagManifests()){ checkHashes(tagManifest); } @@ -158,7 +160,7 @@ void checkHashes(final Manifest manifest) throws CorruptChecksumException, Inter final List exceptions = new ArrayList<>(); for(final Entry entry : manifest.getFileToChecksumMap().entrySet()){ - executor.execute(new CheckManifestHashsTask(entry, manifest.getAlgorithm().getMessageDigestName(), latch, exceptions)); + executor.execute(new CheckManifestHashesTask(entry, manifest.getAlgorithm().getMessageDigestName(), latch, exceptions)); } latch.await(); @@ -166,7 +168,7 @@ void checkHashes(final Manifest manifest) throws CorruptChecksumException, Inter if(!exceptions.isEmpty()){ final Exception e = exceptions.get(0); if(e instanceof CorruptChecksumException){ - logger.debug("[{}] errors occured. At least one of the errors is due to hashes not matching.", exceptions.size()); + logger.debug(messages.getString("checksums_not_matching_error"), exceptions.size()); throw (CorruptChecksumException)e; } @@ -201,7 +203,7 @@ void checkHashes(final Manifest manifest) throws CorruptChecksumException, Inter public void isComplete(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, MissingPayloadManifestException, MissingBagitFileException, MissingPayloadDirectoryException, FileNotInPayloadDirectoryException, InterruptedException, MaliciousPathException, UnsupportedAlgorithmException, InvalidBagitFileFormatException{ - logger.info("Checking if the bag with root directory [{}] is complete.", bag.getRootDir()); + logger.info(messages.getString("checking_bag_is_complete"), bag.getRootDir()); MandatoryVerifier.checkFetchItemsExist(bag.getItemsToFetch(), bag.getRootDir()); diff --git a/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java b/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java index 5e0fb73b4..db377e5e2 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java +++ b/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.text.Normalizer; +import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -17,6 +18,7 @@ @SuppressWarnings(value = {"PMD.DoNotUseThreads"}) public class CheckIfFileExistsTask implements Runnable { private static final Logger logger = LoggerFactory.getLogger(CheckIfFileExistsTask.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private final Path file; //TODO if performance is an issue look at concurrentHashMap - it will take up more space but insertion is O(1) vs O(n) private final Set missingFiles; @@ -35,7 +37,7 @@ public void run() { if(!fileExists){ if(existsNormalized){ - logger.warn("File name [{}] has a different normalization than what is contained on the filesystem!", file); + logger.warn(messages.getString("different_normalization_warning"), file); } else{ missingFiles.add(file); @@ -64,8 +66,7 @@ private boolean existsNormalized(){ } } catch(IOException e){ - logger.error("Error while trying to read [{}] to see if any files in that directory match the normalized " - + "filename of [{}]", parent, normalizedFile, e); + logger.error(messages.getString("error_reading_normalized_file"), parent, normalizedFile, e); } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashsTask.java b/src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashesTask.java similarity index 77% rename from src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashsTask.java rename to src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashesTask.java index a264d2986..fbe82a37e 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashsTask.java +++ b/src/main/java/gov/loc/repository/bagit/verify/CheckManifestHashesTask.java @@ -6,6 +6,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; +import java.util.ResourceBundle; import java.util.Map.Entry; import java.util.concurrent.CountDownLatch; @@ -20,15 +21,16 @@ * 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); +public class CheckManifestHashesTask implements Runnable { + private static final Logger logger = LoggerFactory.getLogger(CheckManifestHashesTask.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private final Entry entry; private final CountDownLatch latch; private final List exceptions; private final String algorithm; - public CheckManifestHashsTask(final Entry entry, final String algorithm, final CountDownLatch latch, final List exceptions) { + public CheckManifestHashesTask(final Entry entry, final String algorithm, final CountDownLatch latch, final List exceptions) { this.entry = entry; this.algorithm = algorithm; this.latch = latch; @@ -48,12 +50,11 @@ public void run() { 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()); + logger.debug(messages.getString("checking_checksums"), entry.getKey(), entry.getValue()); final String hash = Hasher.hash(entry.getKey(), 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 + - " hash of [" + entry.getValue() + "] but was computed [" + hash+"]"); + throw new CorruptChecksumException(messages.getString("corrupt_checksum_error"), entry.getKey(), algorithm, entry.getValue(), hash); } } //if the file doesn't exist it will be caught by checkAllFilesListedInManifestExist method 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 6ab772563..62dfa04dc 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/FileCountAndTotalSizeVistor.java @@ -7,6 +7,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,14 +19,16 @@ */ public class FileCountAndTotalSizeVistor extends SimpleFileVisitor { private static final Logger logger = LoggerFactory.getLogger(FileCountAndTotalSizeVistor.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private long totalSize; private long count; + //TODO allow hidden files/folders? @Override public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { if(PathUtils.isHidden(dir) || dir.endsWith(Paths.get(".bagit"))){ - logger.debug("Skipping {} cause we ignore hidden directories", dir); + logger.debug(messages.getString("skipping_ignored_directory"), dir); return FileVisitResult.SKIP_SUBTREE; } @@ -35,12 +38,12 @@ public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttribut @Override public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) throws IOException{ if(PathUtils.isHidden(path) && !path.endsWith(".keep")){ - logger.debug("Skipping [{}] since we are ignoring hidden files", path); + logger.debug(messages.getString("skipping_hidden_file"), path); } else{ count++; final long size = Files.size(path); - logger.debug("File [{}] hash a size of [{}] bytes", path, size); + logger.debug(messages.getString("file_size_in_bytes"), path, size); totalSize += size; } diff --git a/src/main/java/gov/loc/repository/bagit/verify/MandatoryVerifier.java b/src/main/java/gov/loc/repository/bagit/verify/MandatoryVerifier.java index ea276544a..e73ed3b02 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/MandatoryVerifier.java +++ b/src/main/java/gov/loc/repository/bagit/verify/MandatoryVerifier.java @@ -6,9 +6,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.domain.Bag; import gov.loc.repository.bagit.domain.FetchItem; @@ -24,6 +26,7 @@ */ public final class MandatoryVerifier { private static final Logger logger = LoggerFactory.getLogger(MandatoryVerifier.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); //@Incubating private static final String DOT_BAGIT_DIR_NAME = ".bagit"; @@ -40,10 +43,11 @@ private MandatoryVerifier(){ * @throws FileNotInPayloadDirectoryException if one or more of the fetch items don't exist */ public static 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); + logger.info(messages.getString("checking_fetch_items_exist"), items.size(), bagDir); for(final FetchItem item : items){ if(!Files.exists(item.path)){ - throw new FileNotInPayloadDirectoryException("Fetch item " + item + " has not been fetched!"); + final String formattedMessage = messages.getString("fetch_item_missing_error"); + throw new FileNotInPayloadDirectoryException(MessageFormatter.format(formattedMessage, item).getMessage()); } } } @@ -64,7 +68,8 @@ public static void checkBagitFileExists(final Path rootDir, final Version versio } if(!Files.exists(bagitFile)){ - throw new MissingBagitFileException("File [" + bagitFile + "] should exist but it doesn't"); + final String formattedMessage = messages.getString("file_should_exist_error"); + throw new MissingBagitFileException(MessageFormatter.format(formattedMessage, bagitFile).getMessage()); } } @@ -75,11 +80,11 @@ public static void checkBagitFileExists(final Path rootDir, final Version versio * @throws MissingPayloadDirectoryException if the bag does not contain the payload directory */ public static void checkPayloadDirectoryExists(final Bag bag) throws MissingPayloadDirectoryException{ - logger.info("Checking if special payload directory exists (only for version 0.97 and earlier)"); + logger.info(messages.getString("checking_payload_directory_exists")); final Path dataDir = PathUtils.getDataDir(bag); if(!Files.exists(dataDir)){ - throw new MissingPayloadDirectoryException("File [" + dataDir + "] should exist but it doesn't"); + throw new MissingPayloadDirectoryException(messages.getString("file_should_exist_error")); } } @@ -102,14 +107,14 @@ public static void checkIfAtLeastOnePayloadManifestsExist(final Path rootDir, fi try(DirectoryStream directoryStream = Files.newDirectoryStream(PathUtils.getBagitDir(version, rootDir))){ for(final Path path : directoryStream){ if(PathUtils.getFilename(path).startsWith("manifest-")){ - logger.debug("Found payload manifest file [{}]", path.getFileName()); + logger.debug(messages.getString("found_payload_manifest"), path.getFileName()); hasAtLeastOneManifest = true; } } } if(!hasAtLeastOneManifest){ - throw new MissingPayloadManifestException("Bag does not contain any payload manifest files"); + throw new MissingPayloadManifestException(messages.getString("missing_payload_manifest_error")); } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAllManifestsVistor.java b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAllManifestsVistor.java index 25dfcbe7e..3763f913c 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAllManifestsVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAllManifestsVistor.java @@ -7,6 +7,8 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.Set; +import org.slf4j.helpers.MessageFormatter; + import gov.loc.repository.bagit.domain.Manifest; import gov.loc.repository.bagit.exceptions.FileNotInManifestException; @@ -26,11 +28,12 @@ public FileVisitResult visitFile(final Path path, final BasicFileAttributes attr if(Files.isRegularFile(path)){ for(final Manifest manifest : manifests){ if(!manifest.getFileToChecksumMap().keySet().contains(path.normalize())){ - throw new FileNotInManifestException("File " + path + " is in the payload directory but isn't listed in manifest manifest-" + manifest.getAlgorithm().getBagitName() + ".txt"); + final String formattedMessage = messages.getString("file_not_in_manifest_error"); + throw new FileNotInManifestException(MessageFormatter.format(formattedMessage, path, manifest.getAlgorithm().getBagitName()).getMessage()); } } } - logger.debug("[{}] is in all manifests", path); + logger.debug(messages.getString("file_in_all_manifests"), path); return FileVisitResult.CONTINUE; } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAtLeastOneManifestVistor.java b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAtLeastOneManifestVistor.java index e6d0dad68..0bf8cd0e3 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAtLeastOneManifestVistor.java +++ b/src/main/java/gov/loc/repository/bagit/verify/PayloadFileExistsInAtLeastOneManifestVistor.java @@ -7,6 +7,8 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.Set; +import org.slf4j.helpers.MessageFormatter; + import gov.loc.repository.bagit.exceptions.FileNotInManifestException; /** @@ -23,7 +25,8 @@ public PayloadFileExistsInAtLeastOneManifestVistor(final Set filesListedIn @Override public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs)throws FileNotInManifestException{ if(Files.isRegularFile(path) && !filesListedInManifests.contains(path.normalize())){ - throw new FileNotInManifestException("File " + path + " is in the payload directory but isn't listed in any of the manifests"); + final String formattedMessage = messages.getString("file_not_in_any_manifest_error"); + throw new FileNotInManifestException(MessageFormatter.format(formattedMessage, path).getMessage()); } logger.debug("[{}] is in at least one manifest", path); return FileVisitResult.CONTINUE; diff --git a/src/main/java/gov/loc/repository/bagit/verify/PayloadVerifier.java b/src/main/java/gov/loc/repository/bagit/verify/PayloadVerifier.java index c3beca554..d7ca7b51c 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/PayloadVerifier.java +++ b/src/main/java/gov/loc/repository/bagit/verify/PayloadVerifier.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.HashSet; +import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.CountDownLatch; @@ -13,6 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.domain.Bag; import gov.loc.repository.bagit.domain.Manifest; @@ -31,6 +33,7 @@ */ public class PayloadVerifier { private static final Logger logger = LoggerFactory.getLogger(PayloadVerifier.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private final BagitAlgorithmNameToSupportedAlgorithmMapping nameMapping; private final ExecutorService executor; @@ -115,7 +118,7 @@ public void verifyPayload(final Bag bag, final boolean ignoreHiddenFiles) */ private Set getAllFilesListedInManifests(final Bag bag) throws IOException, MaliciousPathException, UnsupportedAlgorithmException, InvalidBagitFileFormatException { - logger.debug("Getting all files listed in the manifest(s)"); + logger.debug(messages.getString("all_files_in_manifests")); final Set filesListedInManifests = new HashSet<>(); try(DirectoryStream directoryStream = @@ -123,7 +126,7 @@ private Set getAllFilesListedInManifests(final Bag bag) 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); + logger.debug(messages.getString("get_listing_in_manifest"), path); final Manifest manifest = ManifestReader.readManifest(nameMapping, path, bag.getRootDir(), bag.getFileEncoding()); filesListedInManifests.addAll(manifest.getFileToChecksumMap().keySet()); @@ -142,7 +145,7 @@ private void checkAllFilesListedInManifestExist(final Set files) throws Fi final CountDownLatch latch = new CountDownLatch(files.size()); final Set missingFiles = new ConcurrentSkipListSet<>(); - logger.debug("Checking if all files listed in the manifest(s) exist"); + logger.info(messages.getString("check_all_files_in_manifests_exist")); for (final Path file : files) { executor.execute(new CheckIfFileExistsTask(file, missingFiles, latch)); } @@ -150,8 +153,8 @@ private void checkAllFilesListedInManifestExist(final Set files) throws Fi latch.await(); if (!missingFiles.isEmpty()) { - throw new FileNotInPayloadDirectoryException( - "Manifest(s) contains file(s) " + missingFiles + " but they don't exist!"); + final String formattedMessage = messages.getString("missing_payload_files_error"); + throw new FileNotInPayloadDirectoryException(MessageFormatter.format(formattedMessage, missingFiles).getMessage()); } } @@ -160,7 +163,7 @@ private void checkAllFilesListedInManifestExist(final Set files) throws Fi */ private static void checkAllFilesInPayloadDirAreListedInAtLeastOneAManifest(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); + logger.debug(messages.getString("checking_file_in_at_least_one_manifest"), payloadDir); if (Files.exists(payloadDir)) { Files.walkFileTree(payloadDir, new PayloadFileExistsInAtLeastOneManifestVistor(filesListedInManifests, ignoreHiddenFiles)); @@ -172,7 +175,7 @@ private static void checkAllFilesInPayloadDirAreListedInAtLeastOneAManifest(fina */ private static void CheckAllFilesInPayloadDirAreListedInAllManifests(final Set payLoadManifests, final Path payloadDir, final boolean ignoreHiddenFiles) throws IOException { - logger.debug("Checking if all payload files (files in {} dir) are listed in all manifests", payloadDir); + logger.debug(messages.getString("checking_file_in_all_manifests"), payloadDir); if (Files.exists(payloadDir)) { Files.walkFileTree(payloadDir, new PayloadFileExistsInAllManifestsVistor(payLoadManifests, ignoreHiddenFiles)); } diff --git a/src/main/java/gov/loc/repository/bagit/verify/QuickVerifier.java b/src/main/java/gov/loc/repository/bagit/verify/QuickVerifier.java index 48a523c53..2b6689eb1 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/QuickVerifier.java +++ b/src/main/java/gov/loc/repository/bagit/verify/QuickVerifier.java @@ -3,10 +3,12 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ResourceBundle; import java.util.AbstractMap.SimpleImmutableEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.helpers.MessageFormatter; import gov.loc.repository.bagit.domain.Bag; import gov.loc.repository.bagit.exceptions.InvalidPayloadOxumException; @@ -20,6 +22,7 @@ */ public final class QuickVerifier { private static final Logger logger = LoggerFactory.getLogger(QuickVerifier.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private static final String PAYLOAD_OXUM_REGEX = "\\d+\\.\\d+"; private QuickVerifier(){ @@ -34,7 +37,7 @@ private QuickVerifier(){ */ public static boolean canQuickVerify(final Bag bag){ final String payloadOxum = getPayloadOxum(bag); - logger.debug("Found payload-oxum [{}] for bag [{}]", payloadOxum, bag.getRootDir()); + logger.debug(messages.getString("found_payload_oxum"), payloadOxum, bag.getRootDir()); return payloadOxum != null && payloadOxum.matches(PAYLOAD_OXUM_REGEX) && bag.getItemsToFetch().size() == 0; } @@ -64,25 +67,27 @@ private static String getPayloadOxum(final Bag bag){ public static void quicklyVerify(final Bag bag) 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."); + throw new PayloadOxumDoesNotExistException(messages.getString("payload_oxum_missing_error")); } final String[] parts = payloadOxum.split("\\."); - logger.debug("Parsing [{}] for the total byte size of the payload oxum", parts[0]); + logger.debug(messages.getString("parse_size_in_bytes"), 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]); + logger.debug(messages.getString("parse_number_of_files"), parts[1]); final long numberOfFiles = Long.parseLong(parts[1]); final Path payloadDir = PathUtils.getDataDir(bag); final FileCountAndTotalSizeVistor vistor = new FileCountAndTotalSizeVistor(); Files.walkFileTree(payloadDir, vistor); - logger.info("supplied payload-oxum: [{}], Calculated payload-oxum: [{}.{}], for payload directory [{}]", payloadOxum, vistor.getTotalSize(), vistor.getCount(), payloadDir); + logger.debug(messages.getString("compare_payload_oxums"), payloadOxum, vistor.getTotalSize(), vistor.getCount(), payloadDir); if(totalSize != vistor.getTotalSize()){ - throw new InvalidPayloadOxumException("Invalid total size. Expected " + totalSize + "but calculated " + vistor.getTotalSize()); + final String formattedMessage = messages.getString("invalid_total_size_error"); + throw new InvalidPayloadOxumException(MessageFormatter.format(formattedMessage, totalSize, vistor.getTotalSize()).getMessage()); } if(numberOfFiles != vistor.getCount()){ - throw new InvalidPayloadOxumException("Invalid file count. Expected " + numberOfFiles + "but found " + vistor.getCount() + " files"); + final String formattedMessage = messages.getString("invalid_file_cound_error"); + throw new InvalidPayloadOxumException(MessageFormatter.format(formattedMessage, numberOfFiles, vistor.getCount()).getMessage()); } } } 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 c8dc2eba4..239314763 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/BagWriter.java @@ -6,6 +6,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; +import java.util.ResourceBundle; import java.util.Map.Entry; import java.util.Set; @@ -23,6 +24,7 @@ */ public final class BagWriter { private static final Logger logger = LoggerFactory.getLogger(BagWriter.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagWriter(){ //intentionally left empty @@ -41,29 +43,29 @@ private BagWriter(){ * @throws NoSuchAlgorithmException when trying to generate a {@link MessageDigest} which is used during update. */ public static void write(final Bag bag, final Path outputDir) throws IOException, NoSuchAlgorithmException{ - logger.debug("writing payload files"); + logger.debug(messages.getString("writing_payload_files")); final Path bagitDir = PayloadWriter.writeVersionDependentPayloadFiles(bag, outputDir); - logger.debug("Upserting payload-oxum"); + logger.debug(messages.getString("upsert_payload_oxum")); final String payloadOxum = generatePayloadOxum(PathUtils.getDataDir(bag.getVersion(), outputDir)); bag.getMetadata().upsertPayloadOxum(payloadOxum); - logger.debug("writing the bagit.txt file"); + logger.debug(messages.getString("writing_bagit_file")); BagitFileWriter.writeBagitFile(bag.getVersion(), bag.getFileEncoding(), bagitDir); - logger.debug("writing the payload manifest(s)"); + logger.debug(messages.getString("writing_payload_manifests")); ManifestWriter.writePayloadManifests(bag.getPayLoadManifests(), bagitDir, bag.getRootDir(), bag.getFileEncoding()); if(!bag.getMetadata().isEmpty()){ - logger.debug("writing the bag metadata"); + logger.debug(messages.getString("writing_bag_metadata")); MetadataWriter.writeBagMetadata(bag.getMetadata(), bag.getVersion(), bagitDir, bag.getFileEncoding()); } if(bag.getItemsToFetch().size() > 0){ - logger.debug("writing the fetch file"); + logger.debug(messages.getString("writing_fetch_file")); FetchWriter.writeFetchFile(bag.getItemsToFetch(), bagitDir, bag.getRootDir(), bag.getFileEncoding()); } if(bag.getTagManifests().size() > 0){ - logger.debug("writing the tag manifest(s)"); + logger.debug(messages.getString("writing_tag_manifests")); writeTagManifestFiles(bag.getTagManifests(), bagitDir, bag.getRootDir()); final Set updatedTagManifests = updateTagManifests(bag, outputDir); bag.setTagManifests(updatedTagManifests); diff --git a/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java b/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java index 250444289..2d55ee87a 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java @@ -6,6 +6,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +18,7 @@ */ public final class BagitFileWriter { private static final Logger logger = LoggerFactory.getLogger(BagitFileWriter.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private BagitFileWriter(){ //intentionally left empty @@ -33,16 +35,16 @@ private BagitFileWriter(){ */ 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); + logger.debug(messages.getString("write_bagit_file_to_path"), outputDir); final String firstLine = "BagIt-Version: " + version + System.lineSeparator(); - logger.debug("Writing line [{}] to [{}]", firstLine, bagitPath); + logger.debug(messages.getString("writing_line_to_file"), firstLine, bagitPath); Files.write(bagitPath, firstLine.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); final String secondLine = "Tag-File-Character-Encoding: " + encoding + System.lineSeparator(); - logger.debug("Writing line [{}] to [{}]", secondLine, bagitPath); + logger.debug(messages.getString("writing_line_to_file"), secondLine, bagitPath); Files.write(bagitPath, secondLine.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.APPEND); } } diff --git a/src/main/java/gov/loc/repository/bagit/writer/FetchWriter.java b/src/main/java/gov/loc/repository/bagit/writer/FetchWriter.java index 9af439195..30c4c780c 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/FetchWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/FetchWriter.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.List; +import java.util.ResourceBundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,7 +18,8 @@ */ public final class FetchWriter { private static final Logger logger = LoggerFactory.getLogger(FetchWriter.class); - + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); + private FetchWriter(){ //intentionally left empty } @@ -33,12 +35,12 @@ private FetchWriter(){ * @throws IOException if there was a problem writing a file */ public static void writeFetchFile(final List itemsToFetch, final Path outputDir, final Path bagitRootDir, final Charset charsetName) throws IOException{ - logger.debug("Writing fetch.txt to [{}]", outputDir); + logger.debug(messages.getString("writing_fetch_file_to_path"), outputDir); final Path fetchFilePath = outputDir.resolve("fetch.txt"); for(final FetchItem item : itemsToFetch){ final String line = formatFetchLine(item, bagitRootDir); - logger.debug("Writing [{}] to [{}]", line, fetchFilePath); + logger.debug(messages.getString("writing_line_to_file"), line, fetchFilePath); Files.write(fetchFilePath, line.getBytes(charsetName), StandardOpenOption.APPEND, StandardOpenOption.CREATE); } } diff --git a/src/main/java/gov/loc/repository/bagit/writer/ManifestWriter.java b/src/main/java/gov/loc/repository/bagit/writer/ManifestWriter.java index 7d4f5fd18..774b44bbc 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/ManifestWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/ManifestWriter.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.Map.Entry; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -18,6 +19,7 @@ */ public final class ManifestWriter{ private static final Logger logger = LoggerFactory.getLogger(PayloadWriter.class); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private ManifestWriter(){ //intentionally left empty @@ -34,7 +36,7 @@ private ManifestWriter(){ * @throws IOException if there was a problem writing a file */ public static void writePayloadManifests(final Set manifests, final Path outputDir, final Path bagitRootDir, final Charset charsetName) throws IOException{ - logger.info("Writing payload manifest(s)"); + logger.info(messages.getString("writing_payload_manifests")); writeManifests(manifests, outputDir, bagitRootDir, "manifest-", charsetName); } @@ -49,7 +51,7 @@ public static void writePayloadManifests(final Set manifests, final Pa * @throws IOException if there was a problem writing a file */ public static void writeTagManifests(final Set tagManifests, final Path outputDir, final Path bagitRootDir, final Charset charsetName) throws IOException{ - logger.info("Writing tag manifest(s)"); + logger.info(messages.getString("writing_tag_manifests")); writeManifests(tagManifests, outputDir, bagitRootDir, "tagmanifest-", charsetName); } @@ -59,7 +61,7 @@ public static void writeTagManifests(final Set tagManifests, final Pat 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); + logger.debug(messages.getString("writing_manifest_to_path"), manifestPath); Files.deleteIfExists(manifestPath); Files.createFile(manifestPath); @@ -68,7 +70,7 @@ private static void writeManifests(final Set manifests, final Path out //there are 2 spaces between the checksum and the path so that the manifests are compatible with the md5sum tools available on most unix systems. //This may cause problems on windows due to it being text mode, in which case either replace with a * or try verifying in binary mode with --binary final String line = entry.getValue() + " " + RelativePathWriter.formatRelativePathString(relativeTo, entry.getKey()); - logger.debug("Writing [{}] to [{}]", line, manifestPath); + logger.debug(messages.getString("writing_line_to_file"), line, manifestPath); Files.write(manifestPath, line.getBytes(charsetName), StandardOpenOption.APPEND, StandardOpenOption.CREATE); } diff --git a/src/main/java/gov/loc/repository/bagit/writer/MetadataWriter.java b/src/main/java/gov/loc/repository/bagit/writer/MetadataWriter.java index cd7cf6b6a..5f971d41f 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/MetadataWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/MetadataWriter.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.ResourceBundle; import java.util.AbstractMap.SimpleImmutableEntry; import org.slf4j.Logger; @@ -19,6 +20,7 @@ public final class MetadataWriter { private static final Logger logger = LoggerFactory.getLogger(MetadataWriter.class); private static final Version VERSION_0_95 = new Version(0, 95); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private MetadataWriter(){ //intentionall left empty @@ -39,7 +41,7 @@ public static void writeBagMetadata(final Metadata metadata, final Version versi if(version.isSameOrOlder(VERSION_0_95)){ bagInfoFilePath = outputDir.resolve("package-info.txt"); } - logger.debug("Writing {} to [{}]", bagInfoFilePath.getFileName(), outputDir); + logger.debug(messages.getString("writing_metadata_to_path"), bagInfoFilePath.getFileName(), outputDir); Files.deleteIfExists(bagInfoFilePath); final StringBuilder lines = new StringBuilder(); @@ -49,7 +51,7 @@ public static void writeBagMetadata(final Metadata metadata, final Version versi lines.append(line); } - logger.debug("Writing [{}] to [{}]", lines.toString(), bagInfoFilePath); + logger.debug(messages.getString("writing_line_to_file"), lines.toString(), bagInfoFilePath); Files.write(bagInfoFilePath, lines.toString().getBytes(charsetName), StandardOpenOption.APPEND, StandardOpenOption.CREATE); } diff --git a/src/main/java/gov/loc/repository/bagit/writer/PayloadWriter.java b/src/main/java/gov/loc/repository/bagit/writer/PayloadWriter.java index 9a42b08b8..4e3b1df25 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/PayloadWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/PayloadWriter.java @@ -4,6 +4,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.ResourceBundle; import java.util.Set; import org.slf4j.Logger; @@ -19,6 +20,7 @@ public final class PayloadWriter { private static final Logger logger = LoggerFactory.getLogger(PayloadWriter.class); private static final Version VERSION_2_0 = new Version(2, 0); + private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle"); private PayloadWriter(){ //intentionally left empty @@ -54,13 +56,13 @@ static Path writeVersionDependentPayloadFiles(final Bag bag, final Path outputDi * @throws IOException if there was a problem writing a file */ public static void writePayloadFiles(final Set payloadManifests, final Path outputDir, final Path bagDataDir) throws IOException{ - logger.info("Writing payload files"); + logger.info(messages.getString("writing_payload_files")); for(final Manifest payloadManifest : payloadManifests){ for(final Path payloadFile : payloadManifest.getFileToChecksumMap().keySet()){ final Path relativePayloadPath = bagDataDir.relativize(payloadFile); final Path writeToPath = outputDir.resolve(relativePayloadPath); - logger.debug("Writing payload file [{}] to [{}]", payloadFile, writeToPath); + logger.debug(messages.getString("writing_payload_file_to_path"), payloadFile, writeToPath); final Path parent = writeToPath.getParent(); if(parent != null){ Files.createDirectories(parent); diff --git a/src/main/resources/MessageBundle.properties b/src/main/resources/MessageBundle.properties new file mode 100644 index 000000000..6764dd2e9 --- /dev/null +++ b/src/main/resources/MessageBundle.properties @@ -0,0 +1,214 @@ +#default is English, United States (en_US). This is used to store all messages in bagit-java + +#for BagitProfileDeserializer.java +fetch_allowed=Are fetch files allowed? [{}] +serialization_allowed=Serialization is: [{}] +parsing_bagit_profile_info_section=Parsing the BagIt-Profile-Info section +identifier=Identifier is [{}] +source_organization=Source-Organization is [{}] +contact_name=Contact-Name is [{}] +contact_email=Contact-Email is [{}] +external_description=External-Description is [{}] +version=Version is [{}] +parsing_bag_info=Parsing the Bag-Info section +required_manifest_types=Required manifest types {} +acceptable_serialization_mime_types=Acceptable serialization MIME types are {} +required_tagmanifest_types=Required Tagmanifest types are {} +tag_files_required=Tag files required are {} +acceptable_bagit_versions=Acceptable bagit versions are {} + +#for BagitWarning.java +bag_within_a_bag=A data directory can contain anything, including another bag. However it would be better to merge the bags together. +different_case=The bag contains two files that differ only in case. This can cause problems on a filesystem like the one used by apple (HFS). +different_normalization=The bag contains two files that differ only in the normalization. This can cause verification to fail on some systems, and general user confusion. +extra_lines_in_bagit_files=The bagit specification says it must only contain 2 lines. However, some implementations have decided to ignore this which may cause compatibility issues +leading_dot_slash=A manifest lists all data files as relative to the bag root directory, it is superfluous to therefore specify it with a dot. +non_standard_algorithm=The checksum algorithm used does not come standard with the Java runtime. Consider using SHA512 instead. +md5sum_tool_generated_manifest=The manifest was created using a using checksum utilities such as those contained in the GNU Coreutils package (md5sum, sha1sum, etc.), collectively referred to here as 'md5sum'. This creates slight differences in generated manifests that can cause problems in some implementations. +missing_tag_manifest=The tag manifest guards against a truncated payload manifest as well as other potental problems and is always recommened that it be included. +old_bagit_version=The bagit specification version is not the newest. Consider converting to the latest version. +os_specific_files=Files created by the operating system (OS) for its own use. They are non-portable across OS versions and should not be included in any manifest. Examples Thumbs.db on Windows or .DS_Store on OS X +payload_oxum_missing=It is recommended to always include the Payload-Oxum in the bag metadata since it allows for a 'quick verification' of the bag. +tag_files_encoding=It is recommended to always use UTF-8. +weak_checksum_algorithm=The checksum algorithm used is known to be weak. We recommend using SHA512. + +#for BagLinter.java +checking_encoding_problems=Checking encoding problems. +checking_latest_version=checking for latest version. +checking_manifest_problems=checking manifests for problems. +checking_metadata_problems=checking bag metadata for problems. +skipping_check_extra_lines=skipping check for extra lines in bagit files. +checking_extra_lines=checking if [{}] contains more than 2 lines. +extra_lines_warning=The bagit specification states that the bagit.txt file must contain exactly 2 lines. However we found [{}] lines, some implementations will ignore this but may cause incompatibility issues with other tools. + +#for BagProfileChecker.java +checking_fetch_file_allowed=Checking if the fetch file is allowed for bag [{}]. +checking_metadata_entry_required=Checking if [{}] is required in the bag metadata. +check_values_acceptable=Checking if all the values listed for [{}] are acceptable. +check_required_manifests_present=Checking if all the required manifests are present. +required_tag_manifest_type_not_present=Required tagmanifest type [{}] was not present. +required_manifest_type_not_present=Required manifest type [{}] was not present. +checking_required_tag_file_exists=Checking if all the required tag files exist. + +#for BagitVersionIsNotAcceptableException.java +bagit_version_not_acceptable_error=Version [{}] is not in the acceptable list of {}. + +#for RequiredMetadataFieldNotPresentException.java +required_metadata_field_not_present_error=Profile specifies metadata field [{}] is required but was not found! + +#for FetchFileNotAllowedException.java +fetch_file_not_allowed_error=Fetch File was found in bag [{}] + +#for MetadataBalueIsNotAcceptableException.java +metadata_value_not_acceptable_error=Profile specifies that acceptable values for [{}] are {} but found [{}] + +#for RequiredTagFileNotPresentException.java +required_tag_file_not_found_error=Required tag file [{}] was not found + +#for EncodingChecker.java +tag_files_not_encoded_with_utf8_warning=Tag files are encoded with [{}]. We recommend always using UTF-8 instead. + +#For ManifestChecker.java +bag_missing_tag_manifest_warning=Bag [{}] does not contain a tag manifest, which is always recommended. +different_case_warning=In manifest [{}], path [{}] is the same as another path except for the case. This can cause problems if moving the bag to a filesystem that is case insensitive. +manifest_line_violated_spec_error=Manifest contains line [{}] which does not follow the specified form of +md5sum_generated_line_warning=Path [{}] starts with a *, which means it was generated with a non-bagit tool. It is recommended to remove the * in order to conform to the bagit specification. +cannot_access_parent_path_error=Could not access parent folder of [{}]. +different_normalization_warning=File [{}] has a different normalization then what is specified in the manifest. +bag_within_bag_warning=We stronger recommend not storing a bag within a bag as it is known to cause problems. +leading_dot_slash_warning=In manifest [{}] line [{}] is a non-normalized path. +os_specific_files_warning=In manifest [{}] line [{}] contains a OS specific file. +weak_algorithm_warning=Detected a known weak algorithm [{}]. With the great advances in computer hardware there is little penalty to using more bits to calculate the checksum. +non_standard_algorithm_warning=Detected algorithm [{}] which is not included by default in Java. This will make it more difficult to read this bag on some systems. Consider changing it to SHA-512. + +#for MetadataChecker.java +missing_payload_oxum_warning=The Payload-Oxum key was not found in the bag metadata. This will prevent a "quick verify". + +#for VersionChecker.java +old_version_warning=Found version [{}] of the bagit specification but the latest version is [{}]. + +#for AbstractCreateManifestVistor +skipping_hidden_file=Skipping [{}] since we are ignoring hidden files. +skipping_ignored_directory=Skipping [{}] since we are ignoring hidden directories. + +#for BagCreator.java +creating_bag=Creating a bag with version: [{}] in directory: [{}]. +creating_payload_manifests=Creating payload manifest(s). +creating_tag_manifests=Creating tag manifest(s). + +#for Hasher.java +adding_checksum=Adding [{}] to manifest with hash [{}]. + +#for UnsupportedAlgorithmException.java +algorithm_not_supported_error=[{}] is not supported! + +#for BagitTextFileReader.java +reading_version_and_encoding=Reading [{}] for version and encoding. +bagit_version=BagIt-Version is [{}]. +tag_file_encoding=Tag-File-Character-Encoding is [{}]. +invalid_bagit_text_file_error=bagit.txt MUST contain 'BagIt-Version' AND 'Tag-File-Character-Encoding' entries! +bom_present_error=File [{}] contains a byte order mark (BOM) which is not allowed by the bagit specification! + +#for UnparsableVersionException.java +unparsable_version_error=Version must be in format MAJOR.MINOR but was [{}]! + +#for FetchReader.java +reading_fetch_file=Attempting to read [{}]. +read_fetch_file_line=Read URL [{}] length [{}] path [{}] from fetch file [{}]. + +#for KeyValueReader.java +read_key_value_line=Found key [{}] value [{}] in file [{}] using split regex [{}]. +found_indented_line=Found an indented line - merging it with key [{}]. +malformed_key_value_line_error=Line [{}] 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. + +#for ManifestReader.java +attempting_read_manifests=Attempting to find and read manifests. +found_tagmanifest=Found tag manifest [{}]. +found_payload_manifest=Found payload manifest [{}]. +reading_manifest=Reading manifest [{}]. + +#for MetadataReader.java +attempting_read_metadata=Attempting to read bag metadata file. +found_metadata_file=Found metadata file [{}]. + +#for TagFileReader.java +removing_asterisk=Encountered path that was created by non-bagit tool. Removing * from path. Please remove all * from manifest files! +blackslash_used_as_path_separator_error=[{}] is invalid due to the use of the path separactor [\\]! +malicious_path_error=[{}] is trying to be malicious and access a file outside the bag! +invalid_url_format_error=URL [{}] is invalid! + +#for BagVerifier.java +checking_bag_is_valid=Checking if the bag with root directory [{}] is valid. +checking_payload_checksums=Checking payload manifest(s) checksums. +checking_tag_file_checksums=Checking tag manifest(s) checksums. +checksums_not_matching_error=[{}] errors occured. At least one of the errors is due to hashes not matching. +checking_bag_is_complete=Checking if the bag with root directory [{}] is complete. + +#for CheckIfFileExistsTask.java +different_normalization_warning=File name [{}] has a different normalization than what is contained on the filesystem! +error_reading_normalized_file=Error while trying to read [{}] to see if any files in that directory match the normalized filename of [{}]! + +#for CheckManifestHashesTask.java +checking_checksums=Checking file [{}] to see if checksum matches [{}]. + +#for CorruptChecksumException.java +corrupt_checksum_error=File [{}] is suppose to have a [{}] hash of [{}] but was computed [{}]. + +#for FileCoundAndTotalSizeVisitor.java +file_size_in_bytes=File [{}] hash a size of [{}] bytes. + +#for MandatoryVerifier.java +checking_fetch_items_exist=Checking if all [{}] items in fetch.txt exist in the [{}] directory. +fetch_item_missing_error=Fetch item [{}] has not been fetched! +file_should_exist_error=File [{}] should exist but it doesn't! +checking_payload_directory_exists=Checking if special payload directory exists (only for version 0.97 and earlier). + +#for MissingPayloadManifestException.java +missing_payload_manifest_error=Bag does not contain a payload manifest file! + +#for PayloadFileExistsInAllManifestsVistor.java +file_not_in_manifest_error=File [{}] is in the payload directory but isn't listed in manifest manifest-{}.txt! +file_in_all_manifests=[{}] is in all manifests. +file_not_in_any_manifest_error=File [{}] is in the payload directory but isn't listed in any manifest! + +#for PayloadVerifier.java +all_files_in_manifests=Getting all files listed in the manifest(s). +get_listing_in_manifest=Getting files and checksums listed in [{}]. +check_all_files_in_manifests_exist=Checking if all files listed in the manifest(s) exist. +missing_payload_files_error=Manifest(s) contains file(s) {} but they don't exist! +checking_file_in_at_least_one_manifest=Checking if all payload files (files in [{}] directory) are listed in at least one manifest. +checking_file_in_all_manifests=Checking if all payload files (files in [{}] directory) are listed in all manifests. + +#for QuickVerifier.java +found_payload_oxum=Found payload-oxum [{}] for bag [{}]. +payload_oxum_missing_error=Payload-Oxum does not exist in bag! +parse_size_in_bytes=Parsing [{}] for the total byte size of the payload oxum. +parse_number_of_files=Parsing [{}] for the number of files to find in the payload directory. +compare_payload_oxums=supplied payload-oxum: [{}], Calculated payload-oxum: [{}.{}], for payload directory [{}]. +invalid_total_size_error=Invalid total size. Expected [{}] but calculated [{}]! +invalid_file_cound_error=Invalid file count. Expected [{}] but found [{}]! + +#for BagitFileWriter.java +write_bagit_file_to_path=Writing bagit.txt file to [{}] +writing_line_to_file=Writing line [{}] to [{}] + +#for BagWriter.java +writing_payload_files=Writing payload files. +upsert_payload_oxum=Upserting payload-oxum. +writing_bagit_file=Writing the bagit.txt file. +writing_payload_manifests=Writing the payload manifest(s). +writing_bag_metadata=Writing the bag metadata. +writing_fetch_file=Writing the fetch file. +writing_tag_manifests=Writing the tag manifest(s). + +#for FetchWriter.java +writing_fetch_file_to_path=Writing fetch.txt to [{}]. + +#for ManifestWriter.java +writing_manifest_to_path=Writing manifest to [{}]. + +#for MetadataWriter.java +writing_metadata_to_path=Writing bag metadata file [{}] to [{}]. + +#for PayloadWriter.java +writing_payload_file_to_path=Writing payload file [{}] to [{}]. \ No newline at end of file diff --git a/src/test/java/gov/loc/repository/bagit/conformance/ManifestCheckerTest.java b/src/test/java/gov/loc/repository/bagit/conformance/ManifestCheckerTest.java index c5460c83f..690c8e78c 100644 --- a/src/test/java/gov/loc/repository/bagit/conformance/ManifestCheckerTest.java +++ b/src/test/java/gov/loc/repository/bagit/conformance/ManifestCheckerTest.java @@ -43,7 +43,7 @@ public void testCheckManifests() throws Exception{ assertTrue(warnings.contains(BagitWarning.LEADING_DOT_SLASH)); assertTrue(warnings.contains(BagitWarning.NON_STANDARD_ALGORITHM)); assertTrue(warnings.contains(BagitWarning.OS_SPECIFIC_FILES)); - assertTrue(warnings.contains(BagitWarning.MISSING_TAG_MANIEST)); + assertTrue(warnings.contains(BagitWarning.MISSING_TAG_MANIFEST)); } @Test @@ -52,7 +52,7 @@ public void testCheckTagManifest() throws Exception{ Set warnings = new HashSet<>(); ManifestChecker.checkManifests(folder.getRoot().toPath(), StandardCharsets.UTF_16, warnings, Collections.emptyList()); - assertFalse(warnings.contains(BagitWarning.MISSING_TAG_MANIEST)); + assertFalse(warnings.contains(BagitWarning.MISSING_TAG_MANIFEST)); } @Test From e2e2a7004c3eddd86085535e0ab39e1f92219c66 Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 27 Apr 2017 07:48:28 -0400 Subject: [PATCH 2/5] increase code coverage by testing private constructor --- .../repository/bagit/reader/KeyValueReaderTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/gov/loc/repository/bagit/reader/KeyValueReaderTest.java b/src/test/java/gov/loc/repository/bagit/reader/KeyValueReaderTest.java index f9dff4e8a..2b904c9ee 100644 --- a/src/test/java/gov/loc/repository/bagit/reader/KeyValueReaderTest.java +++ b/src/test/java/gov/loc/repository/bagit/reader/KeyValueReaderTest.java @@ -1,15 +1,21 @@ package gov.loc.repository.bagit.reader; +import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; -import org.junit.Assert; import org.junit.Test; +import gov.loc.repository.bagit.PrivateConstructorTest; import gov.loc.repository.bagit.exceptions.InvalidBagMetadataException; -public class KeyValueReaderTest extends Assert { +public class KeyValueReaderTest extends PrivateConstructorTest { + + @Test + public void testClassIsWellDefined() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException{ + assertUtilityClassWellDefined(KeyValueReader.class); + } @Test(expected=InvalidBagMetadataException.class) public void testReadInproperIndentedBagMetadataFileThrowsException() throws Exception{ From 63479fafd374c801cef9482fc153df7f1cf2f91b Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 27 Apr 2017 12:14:40 -0400 Subject: [PATCH 3/5] refs #89 - added task to check messageBundle for duplicate entries and that all entries are used --- code-quality.gradle | 56 ++++++++++++++++++- .../bagit/conformance/ManifestChecker.java | 2 +- .../bagit/verify/CheckIfFileExistsTask.java | 2 +- .../bagit/writer/BagitFileWriter.java | 1 - src/main/resources/MessageBundle.properties | 4 +- 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/code-quality.gradle b/code-quality.gradle index 974fc9e48..8600f8838 100644 --- a/code-quality.gradle +++ b/code-quality.gradle @@ -97,4 +97,58 @@ dependencyCheck { // xml.enabled = false // html.enabled = true // } -//} \ No newline at end of file +//} + +import java.util.Map.Entry; +task checkMessageBundle(){ + inputs.files(fileTree(dir: "src/main/resources", include: "**/MessageBundle*.properties")) + outputs.dir("$buildDir/checkMessageBundle") //hack: define a output dir so gradle will check if up-to-date + + doLast{ + Set messageKeys = new HashSet<>() + + inputs.getFiles().each{File file -> + file.eachLine {String line -> + if(line && !line.trim().startsWith('#')){ + String[] keyValue = checkMessageBundleLineIsCorrectlyFormatted(line, file) + + if(messageKeys.contains(keyValue[0])){ + throw new GradleException("Internationalization message bundle contains duplicate key [${keyValue[0]}]!") + } + messageKeys.add(keyValue[0]) + } + } + } + + checkAllMessageKeysAreUsed(messageKeys) + } +} +check.dependsOn checkMessageBundle + +String[] checkMessageBundleLineIsCorrectlyFormatted(String line, File file){ + String[] keyValue = line.split("=", 2) + + if(keyValue.size() != 2 || keyValue[1].isEmpty()){ + throw new GradleException("Line [${line}] in file [${file}] is not a valid entry for the internationalization message bundle!") + } + + return keyValue +} + +void checkAllMessageKeysAreUsed(Set messageKeys){ + sourceSets.main.allJava.each { File file -> + file.eachLine{ String line -> + for(String key : messageKeys.clone()){ + if(line.contains(key)){ + messageKeys.remove(key) + } + } + } + } + + if(messageKeys.size() > 0){ + messageKeys.each{String key -> + throw new GradleException("[${key}] is listed in the internationalization message bundle but never actually used!") + } + } +} \ No newline at end of file diff --git a/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java b/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java index ee0310750..d847e6413 100644 --- a/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java +++ b/src/main/java/gov/loc/repository/bagit/conformance/ManifestChecker.java @@ -149,7 +149,7 @@ private static void checkNormalization(final String path, final Path rootDir, fi final String normalizedFile = normalizePathToNFD(file); if(!file.equals(fileToCheck) && normalizedFileToCheck.equals(normalizedFile)){ - logger.warn(messages.getString("different_normalization_warning"), fileToCheck); + logger.warn(messages.getString("different_normalization_in_manifest_warning"), fileToCheck); warnings.add(BagitWarning.DIFFERENT_NORMALIZATION); } } diff --git a/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java b/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java index db377e5e2..7caf60009 100644 --- a/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java +++ b/src/main/java/gov/loc/repository/bagit/verify/CheckIfFileExistsTask.java @@ -37,7 +37,7 @@ public void run() { if(!fileExists){ if(existsNormalized){ - logger.warn(messages.getString("different_normalization_warning"), file); + logger.warn(messages.getString("different_normalization_on_filesystem_warning"), file); } else{ missingFiles.add(file); diff --git a/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java b/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java index 2d55ee87a..41aedb7b9 100644 --- a/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java +++ b/src/main/java/gov/loc/repository/bagit/writer/BagitFileWriter.java @@ -37,7 +37,6 @@ public static void writeBagitFile(final Version version, final Charset encoding, final Path bagitPath = outputDir.resolve("bagit.txt"); logger.debug(messages.getString("write_bagit_file_to_path"), outputDir); - final String firstLine = "BagIt-Version: " + version + System.lineSeparator(); logger.debug(messages.getString("writing_line_to_file"), firstLine, bagitPath); Files.write(bagitPath, firstLine.getBytes(StandardCharsets.UTF_8), diff --git a/src/main/resources/MessageBundle.properties b/src/main/resources/MessageBundle.properties index 6764dd2e9..5684987ca 100644 --- a/src/main/resources/MessageBundle.properties +++ b/src/main/resources/MessageBundle.properties @@ -74,7 +74,7 @@ different_case_warning=In manifest [{}], path [{}] is the same as another path e manifest_line_violated_spec_error=Manifest contains line [{}] which does not follow the specified form of md5sum_generated_line_warning=Path [{}] starts with a *, which means it was generated with a non-bagit tool. It is recommended to remove the * in order to conform to the bagit specification. cannot_access_parent_path_error=Could not access parent folder of [{}]. -different_normalization_warning=File [{}] has a different normalization then what is specified in the manifest. +different_normalization_in_manifest_warning=File [{}] has a different normalization then what is specified in the manifest. bag_within_bag_warning=We stronger recommend not storing a bag within a bag as it is known to cause problems. leading_dot_slash_warning=In manifest [{}] line [{}] is a non-normalized path. os_specific_files_warning=In manifest [{}] line [{}] contains a OS specific file. @@ -145,7 +145,7 @@ checksums_not_matching_error=[{}] errors occured. At least one of the errors is checking_bag_is_complete=Checking if the bag with root directory [{}] is complete. #for CheckIfFileExistsTask.java -different_normalization_warning=File name [{}] has a different normalization than what is contained on the filesystem! +different_normalization_on_filesystem_warning=File name [{}] has a different normalization than what is contained on the filesystem! error_reading_normalized_file=Error while trying to read [{}] to see if any files in that directory match the normalized filename of [{}]! #for CheckManifestHashesTask.java From 463be8530d5f7e68041ac7717b0a36219f8b320f Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 27 Apr 2017 12:31:02 -0400 Subject: [PATCH 4/5] refs #89 - updated readme to include info about how to help with translating --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3f55ce47a..3e69a9efc 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,9 @@ this functionality, the demonstrates how you can implement this feature with your additional application and workflow requirements. +##### Internationalization +All logging and error messages have been put into a [ResourceBundle](https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html). This allows for all the messages to be translated to multiple languages and automatically used during runtime. If you would like to contribute to translations please visit https://www.transifex.com/acdha/bagit/dashboard/ + ##### New Interfaces The 5.x version is a complete rewrite of the bagit-java library which attempts @@ -170,3 +173,4 @@ Simply run `gradle eclipse` and it will automatically create a eclipse project f ### Roadmap for this library * Further refine reading and writing of bags version 0.93-0.97 * Fix bugs/issues reported with new library (on going) +* Translate to various languages (on going) From 068ddfbb3cf5d8a03e9108a59d9f637ff26c7e02 Mon Sep 17 00:00:00 2001 From: John Scancella Date: Thu, 27 Apr 2017 13:52:52 -0400 Subject: [PATCH 5/5] refs #89 - updated link to transifex for bagit-java --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e69a9efc..9b73c075d 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,9 @@ demonstrates how you can implement this feature with your additional application and workflow requirements. ##### Internationalization -All logging and error messages have been put into a [ResourceBundle](https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html). This allows for all the messages to be translated to multiple languages and automatically used during runtime. If you would like to contribute to translations please visit https://www.transifex.com/acdha/bagit/dashboard/ +All logging and error messages have been put into a [ResourceBundle](https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html). +This allows for all the messages to be translated to multiple languages and automatically used during runtime. +If you would like to contribute to translations please visit https://www.transifex.com/acdha/bagit-java/dashboard/ ##### New Interfaces