Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

as per the proposed spec, allow for payload-oxum to be in bagit.txt #80

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/main/java/gov/loc/repository/bagit/creator/BagCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import gov.loc.repository.bagit.domain.Version;
import gov.loc.repository.bagit.hash.Hasher;
import gov.loc.repository.bagit.hash.SupportedAlgorithm;
import gov.loc.repository.bagit.util.PathUtils;
import gov.loc.repository.bagit.writer.BagitFileWriter;
import gov.loc.repository.bagit.writer.ManifestWriter;

Expand All @@ -26,6 +27,8 @@
*/
public final class BagCreator {
private static final Logger logger = LoggerFactory.getLogger(BagCreator.class);
private static final int LATEST_MAJOR_VERSION = 0;
private static final int LATEST_MINOR_VERSION = 97;

private BagCreator(){}

Expand All @@ -42,11 +45,11 @@ private BagCreator(){}
* @return a {@link Bag} object representing the newly created bagit bag
*/
public static Bag bagInPlace(final Path root, final Collection<SupportedAlgorithm> algorithms, final boolean includeHidden) throws NoSuchAlgorithmException, IOException{
final Bag bag = new Bag(new Version(0, 97));
final Bag bag = new Bag(new Version(LATEST_MAJOR_VERSION, LATEST_MINOR_VERSION));
bag.setRootDir(root);
logger.info("Creating a bag with version: [{}] in directory: [{}]", bag.getVersion(), root);

final Path dataDir = root.resolve("data");
final Path dataDir = PathUtils.getDataDir(bag);
Files.createDirectory(dataDir);
final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(root);
for(final Path path : directoryStream){
Expand All @@ -61,7 +64,7 @@ public static Bag bagInPlace(final Path root, final Collection<SupportedAlgorith
Files.walkFileTree(dataDir, payloadVisitor);

bag.getPayLoadManifests().addAll(payloadFilesMap.keySet());
BagitFileWriter.writeBagitFile(bag.getVersion(), bag.getFileEncoding(), root);
BagitFileWriter.writeBagitFile(bag.getVersion(), bag.getFileEncoding(), null, null, root);
ManifestWriter.writePayloadManifests(bag.getPayLoadManifests(), root, root, bag.getFileEncoding());

logger.info("Creating tag manifest(s)");
Expand Down Expand Up @@ -102,7 +105,7 @@ public static Bag createDotBagit(final Path root, final Collection<SupportedAlgo
Files.walkFileTree(root, visitor);

bag.getPayLoadManifests().addAll(map.keySet());
BagitFileWriter.writeBagitFile(bag.getVersion(), bag.getFileEncoding(), dotbagitDir);
BagitFileWriter.writeBagitFile(bag.getVersion(), bag.getFileEncoding(), null, null, dotbagitDir);
ManifestWriter.writePayloadManifests(bag.getPayLoadManifests(), dotbagitDir, root, bag.getFileEncoding());

logger.info("Creating tag manifest(s)");
Expand Down
89 changes: 45 additions & 44 deletions src/main/java/gov/loc/repository/bagit/domain/Bag.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,50 +66,6 @@ public Bag(final Bag bag){
this.rootDir = bag.getRootDir();
}

public Version getVersion(){
return version;
}

public Set<Manifest> getPayLoadManifests() {
return payLoadManifests;
}

public void setPayLoadManifests(final Set<Manifest> payLoadManifests) {
this.payLoadManifests = payLoadManifests;
}

public Set<Manifest> getTagManifests() {
return tagManifests;
}

public void setTagManifests(final Set<Manifest> tagManifests) {
this.tagManifests = tagManifests;
}

public List<FetchItem> getItemsToFetch() {
return itemsToFetch;
}

public void setItemsToFetch(final List<FetchItem> itemsToFetch) {
this.itemsToFetch = itemsToFetch;
}

public List<SimpleImmutableEntry<String, String>> getMetadata() {
return metadata;
}

public void setMetadata(final List<SimpleImmutableEntry<String, String>> metadata) {
this.metadata = metadata;
}

public Charset getFileEncoding() {
return fileEncoding;
}

public void setFileEncoding(final Charset fileEncoding) {
this.fileEncoding = fileEncoding;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder(95);
Expand Down Expand Up @@ -155,6 +111,50 @@ public boolean equals(final Object obj) {
Objects.equals(this.itemsToFetch, other.getItemsToFetch()) &&
Objects.equals(this.metadata, other.getMetadata());
}

public Version getVersion(){
return version;
}

public Set<Manifest> getPayLoadManifests() {
return payLoadManifests;
}

public void setPayLoadManifests(final Set<Manifest> payLoadManifests) {
this.payLoadManifests = payLoadManifests;
}

public Set<Manifest> getTagManifests() {
return tagManifests;
}

public void setTagManifests(final Set<Manifest> tagManifests) {
this.tagManifests = tagManifests;
}

public List<FetchItem> getItemsToFetch() {
return itemsToFetch;
}

public void setItemsToFetch(final List<FetchItem> itemsToFetch) {
this.itemsToFetch = itemsToFetch;
}

public List<SimpleImmutableEntry<String, String>> getMetadata() {
return metadata;
}

public void setMetadata(final List<SimpleImmutableEntry<String, String>> metadata) {
this.metadata = metadata;
}

public Charset getFileEncoding() {
return fileEncoding;
}

public void setFileEncoding(final Charset fileEncoding) {
this.fileEncoding = fileEncoding;
}

public Path getRootDir() {
return rootDir;
Expand All @@ -167,4 +167,5 @@ public void setRootDir(final Path rootDir) {
public void setVersion(final Version version) {
this.version = version;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/**
* The {@link Bag} object should contain the Payload-Oxum metatdata key value pair,
* this class represents the error when trying to calculate the payload-oxum and it doesn't exist on the bag object.
* Or if the payload-byte-count and payload-file-count don't exist for versions 1.0+
*/
public class PayloadOxumDoesNotExistException extends RuntimeException {
private static final long serialVersionUID = 1L;
Expand Down
35 changes: 35 additions & 0 deletions src/main/java/gov/loc/repository/bagit/reader/BagitFileValues.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gov.loc.repository.bagit.reader;

import java.nio.charset.Charset;

import gov.loc.repository.bagit.domain.Version;

/**
* A simple data object for passing around all the bagit.txt file values
*/
public class BagitFileValues {
private final Version version;
private final Charset encoding;
private final Long payloadByteCount;
private final Long payloadFileCount;

public BagitFileValues(final Version version, final Charset encoding, final Long payloadByteCount, final Long payloadFileCount){
this.version = version;
this.encoding = encoding;
this.payloadByteCount = payloadByteCount;
this.payloadFileCount = payloadFileCount;
}

public Version getVersion() {
return version;
}
public Charset getEncoding() {
return encoding;
}
public Long getPayloadByteCount() {
return payloadByteCount;
}
public Long getPayloadFileCount() {
return payloadFileCount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -32,23 +32,67 @@ private BagitTextFileReader(){
* @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec
*/
public static SimpleImmutableEntry<Version, Charset> readBagitTextFile(final Path bagitFile) throws IOException, UnparsableVersionException, InvalidBagMetadataException{
final BagitFileValues values = parseValues(bagitFile);

return new SimpleImmutableEntry<Version, Charset>(values.getVersion(), values.getEncoding());
}

/**
* Read the Payload-Byte-Count and Payload-File-Count from the bagit.txt file
* @since bagic specification 1.0
*
* @param bagitFile the bagit.txt file to read
*
* @return the payload byte count, payload file count (in that order)
*
* @throws IOException if there is a problem reading a file
* @throws UnparsableVersionException if there is a problem parsing the bagit version number
* @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec
*/
public static SimpleImmutableEntry<Long, Long> readPayloadByteAndFileCount(final Path bagitFile) throws UnparsableVersionException, IOException, InvalidBagMetadataException{
final BagitFileValues values = parseValues(bagitFile);

return new SimpleImmutableEntry<Long, Long>(values.getPayloadByteCount(), values.getPayloadFileCount());
}

/**
* Read version, file encoding, and (possibly) payload byte and file count
*
* @param bagitFile the bagit.txt file to read
*
* @return all the possible bagit.txt file field values
*
* @throws IOException if there is a problem reading a file
* @throws UnparsableVersionException if there is a problem parsing the bagit version number
* @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec
*/
public static BagitFileValues parseValues(final Path bagitFile) throws UnparsableVersionException, IOException, InvalidBagMetadataException{
logger.debug("Reading [{}] file", bagitFile);
final List<SimpleImmutableEntry<String, String>> pairs = KeyValueReader.readKeyValuesFromFile(bagitFile, ":", StandardCharsets.UTF_8);

String version = "";

Version version = null;
Charset encoding = StandardCharsets.UTF_8;
Long payloadByteCount = null;
Long payloadFileCount = null;

for(final SimpleImmutableEntry<String, String> pair : pairs){
if("BagIt-Version".equals(pair.getKey())){
version = pair.getValue();
logger.debug("BagIt-Version is [{}]", version);
version = parseVersion(pair.getValue());
}
if("Tag-File-Character-Encoding".equals(pair.getKey())){
encoding = Charset.forName(pair.getValue());
logger.debug("Tag-File-Character-Encoding is [{}]", encoding);
}
if("Payload-Byte-Count".equals(pair.getKey())){ //assume version is 1.0+
payloadByteCount = Long.valueOf(pair.getValue());
}
if("Payload-File-Count".equals(pair.getKey())){ //assume version is 1.0+
payloadFileCount = Long.valueOf(pair.getValue());
}
logger.debug("[{}] is [{}]", pair.getKey(), pair.getValue());
}

return new SimpleImmutableEntry<Version, Charset>(parseVersion(version), encoding);
return new BagitFileValues(version, encoding, payloadByteCount, payloadFileCount);
}

/*
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/gov/loc/repository/bagit/util/PathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ public static boolean isHidden(final Path path) throws IOException{
return Files.isHidden(path);
}

/*
* Get the directory that contains the payload files.
*/
/**
* With bagit version 2.0 (.bagit)
* payload files are no longer in the "data" directory. This method accounts for this
Expand Down
16 changes: 12 additions & 4 deletions src/main/java/gov/loc/repository/bagit/verify/BagVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
import gov.loc.repository.bagit.domain.Manifest;
import gov.loc.repository.bagit.exceptions.CorruptChecksumException;
import gov.loc.repository.bagit.exceptions.FileNotInPayloadDirectoryException;
import gov.loc.repository.bagit.exceptions.InvalidBagMetadataException;
import gov.loc.repository.bagit.exceptions.InvalidBagitFileFormatException;
import gov.loc.repository.bagit.exceptions.InvalidPayloadOxumException;
import gov.loc.repository.bagit.exceptions.MaliciousPathException;
import gov.loc.repository.bagit.exceptions.MissingBagitFileException;
import gov.loc.repository.bagit.exceptions.MissingPayloadDirectoryException;
import gov.loc.repository.bagit.exceptions.MissingPayloadManifestException;
import gov.loc.repository.bagit.exceptions.PayloadOxumDoesNotExistException;
import gov.loc.repository.bagit.exceptions.UnparsableVersionException;
import gov.loc.repository.bagit.exceptions.UnsupportedAlgorithmException;
import gov.loc.repository.bagit.exceptions.VerificationException;
import gov.loc.repository.bagit.hash.BagitAlgorithmNameToSupportedAlgorithmMapping;
Expand Down Expand Up @@ -61,8 +63,12 @@ public BagVerifier(final ExecutorService executor, final BagitAlgorithmNameToSup
*
* @param bag the {@link Bag} object you wish to check
* @return true if the bag can be quickly verified
*
* @throws IOException if there is a problem reading a file
* @throws UnparsableVersionException if there is a problem parsing the bagit version number
* @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec
*/
public boolean canQuickVerify(final Bag bag){
public boolean canQuickVerify(final Bag bag) throws UnparsableVersionException, IOException, InvalidBagMetadataException{
return QuickVerifier.canQuickVerify(bag);
}

Expand All @@ -72,13 +78,15 @@ public boolean canQuickVerify(final Bag bag){
* @param bag the bag to verify by payload-oxum
* @param ignoreHiddenFiles ignore hidden files found in payload directory
*
* @throws IOException if there is an error reading a file
* @throws InvalidPayloadOxumException if either the total bytes or the number of files
* calculated for the payload directory of the bag is different than the supplied values
* @throws IOException if there is a problem reading a file
* @throws UnparsableVersionException if there is a problem parsing the bagit version number
* @throws InvalidBagMetadataException if the bagit.txt file does not conform to the bagit spec
* @throws PayloadOxumDoesNotExistException if the bag does not contain a payload-oxum.
* To check, run {@link BagVerifier#canQuickVerify}
*/
public void quicklyVerify(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, InvalidPayloadOxumException{
public void quicklyVerify(final Bag bag, final boolean ignoreHiddenFiles) throws IOException, InvalidPayloadOxumException, UnparsableVersionException, InvalidBagMetadataException{
QuickVerifier.quicklyVerify(bag, ignoreHiddenFiles);
}

Expand Down Expand Up @@ -150,7 +158,7 @@ void checkHashes(final Manifest manifest) throws CorruptChecksumException, Inter
* <li>every element is present
* <li>every file in the payload manifest(s) are present
* <li>every file in the tag manifest(s) are present. Tag files not listed in a tag manifest may be present.
* <li>every file in the data directory must be listed in at least one payload manifest
* <li>every file in the payload directory must be listed in at least one payload manifest
* <li>each element must comply with the bagit spec
* </ul>
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private MandatoryVerifier(){
}

/**
* make sure all the fetch items exist in the data directory
* make sure all the fetch items exist in the payload directory
*
* @param items the items that needed to be fetched for the bag to be complete
* @param bagDir the root directory of the bag
Expand Down Expand Up @@ -76,8 +76,8 @@ 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)");
final Path dataDir = PathUtils.getDataDir(bag);
logger.info("Checking if payload directory [{}] exists", dataDir);

if(!Files.exists(dataDir)){
throw new MissingPayloadDirectoryException("File [" + dataDir + "] should exist but it doesn't");
Expand Down
Loading