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

Adapt parsing Bagit Profile due to specification. #128

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public class BagInfoRequirement {
private boolean required;
private List<String> acceptableValues = new ArrayList<>();
private boolean repeatable;
private boolean repeatable = true;
VolkerHartmann marked this conversation as resolved.
Show resolved Hide resolved

@Override
public boolean equals(final Object other) {
Expand All @@ -37,6 +37,12 @@ public BagInfoRequirement(final boolean required, final List<String> acceptableV
this.acceptableValues = acceptableValues;
}

public BagInfoRequirement(final boolean required, final List<String> acceptableValues, final boolean repeatable){
this.required = required;
this.acceptableValues = acceptableValues;
this.repeatable = repeatable;
}

@Override
public String toString() {
return "[required=" + required + ", acceptableValues=" + acceptableValues + ", repeatable=" + repeatable + "]";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class BagitProfile {
private String externalDescription = "";
private String contactName = "";
private String contactEmail = "";
private String contactPhone = "";
private String version = "";

private Map<String, BagInfoRequirement> bagInfoRequirements = new HashMap<>();
Expand All @@ -38,6 +39,7 @@ public boolean equals(final Object other) {
&& Objects.equals(sourceOrganization, castOther.sourceOrganization)
&& Objects.equals(externalDescription, castOther.externalDescription)
&& Objects.equals(contactName, castOther.contactName) && Objects.equals(contactEmail, castOther.contactEmail)
&& Objects.equals(contactPhone, castOther.contactPhone)
&& Objects.equals(version, castOther.version)
&& Objects.equals(bagInfoRequirements, castOther.bagInfoRequirements)
&& Objects.equals(manifestTypesRequired, castOther.manifestTypesRequired)
Expand All @@ -50,15 +52,14 @@ public boolean equals(final Object other) {
}
@Override
public int hashCode() {
return Objects.hash(bagitProfileIdentifier, sourceOrganization, externalDescription, contactName, contactEmail,
version, bagInfoRequirements, manifestTypesRequired, fetchFileAllowed, serialization,
return Objects.hash(bagitProfileIdentifier, sourceOrganization, externalDescription, contactName, contactEmail, contactPhone, version, bagInfoRequirements, manifestTypesRequired, fetchFileAllowed, serialization,
acceptableMIMESerializationTypes, acceptableBagitVersions, tagManifestTypesRequired, tagFilesRequired);
}
@Override
public String toString() {
return "BagitProfile [bagitProfileIdentifier=" + bagitProfileIdentifier + ", sourceOrganization="
+ sourceOrganization + ", externalDescription=" + externalDescription + ", contactName=" + contactName
+ ", contactEmail=" + contactEmail + ", version=" + version + ", bagInfoRequirements=" + bagInfoRequirements
+ ", contactEmail=" + contactEmail + ", contactPhone=" + contactPhone + ", version=" + version + ", bagInfoRequirements=" + bagInfoRequirements
+ ", manifestTypesRequired=" + manifestTypesRequired + ", fetchFileAllowed=" + fetchFileAllowed
+ ", serialization=" + serialization + ", acceptableMIMESerializationTypes=" + acceptableMIMESerializationTypes
+ ", acceptableBagitVersions=" + acceptableBagitVersions + ", tagManifestTypesRequired="
Expand Down Expand Up @@ -143,6 +144,12 @@ public String getContactEmail() {
public void setContactEmail(final String contactEmail) {
this.contactEmail = contactEmail;
}
public String getContactPhone() {
return contactPhone;
}
public void setContactPhone(final String contactPhone) {
this.contactPhone = contactPhone;
}
public String getVersion() {
return version;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

/**
* Deserialize bagit profile json to a {@link BagitProfile}
* Deserialize bagit profile json to a {@link BagitProfile}
*/
public class BagitProfileDeserializer extends StdDeserializer<BagitProfile> {

private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(BagitProfileDeserializer.class);
private static final ResourceBundle messages = ResourceBundle.getBundle("MessageBundle");
Expand All @@ -36,149 +37,176 @@ public BagitProfileDeserializer(final Class<?> vc) {

@Override
public BagitProfile deserialize(final JsonParser p, final DeserializationContext ctxt)
throws IOException, JsonProcessingException {
throws IOException, JsonProcessingException {
final BagitProfile profile = new BagitProfile();
final JsonNode node = p.getCodec().readTree(p);

parseBagitProfileInfo(node, profile);

profile.setBagInfoRequirements(parseBagInfo(node));

profile.getManifestTypesRequired().addAll(parseManifestTypesRequired(node));

profile.setFetchFileAllowed(node.get("Allow-Fetch.txt").asBoolean());
logger.debug(messages.getString("fetch_allowed"), profile.isFetchFileAllowed());

profile.setSerialization(Serialization.valueOf(node.get("Serialization").asText()));
logger.debug(messages.getString("serialization_allowed"),profile.getSerialization());
logger.debug(messages.getString("serialization_allowed"), profile.getSerialization());

profile.getAcceptableMIMESerializationTypes().addAll(parseAcceptableSerializationFormats(node));

profile.getTagManifestTypesRequired().addAll(parseRequiredTagmanifestTypes(node));

profile.getTagFilesRequired().addAll(parseRequiredTagFiles(node));

profile.getAcceptableBagitVersions().addAll(parseAcceptableVersions(node));

return profile;
}
private static void parseBagitProfileInfo(final JsonNode node, final BagitProfile profile){

private static void parseBagitProfileInfo(final JsonNode node, final BagitProfile profile) {
final JsonNode bagitProfileInfoNode = node.get("BagIt-Profile-Info");
logger.debug(messages.getString("parsing_bagit_profile_info_section"));


// Read required tags first
// due to specification defined at https://github.com/bagit-profiles/bagit-profiles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure what this comment means. Why do you need to read required tags first?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First the required tags are read and then the optional tags because they have to be handled differently. It's just to keep the code clearer.
If one of the required ones do not already exist, the optional ones are no longer read at all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless there is an error being thrown that I don't know about, how are you stopping if a required tag is missing? To put it another way, what would break if you moved those if not null statements to being read first?

Perhaps a better way to make it cleaner would be to make another method that contained all the reads for optional tags. Something like

    final JsonNode contactNameNode = bagitProfileInfoNode.get("Contact-Name");
    if (contactNameNode != null) {
      final String contactName = contactNameNode.asText();
      logger.debug(messages.getString("contact_name"), contactName);
      profile.setContactName(contactName);
    }
     final JsonNode contactEmailNode = bagitProfileInfoNode.get("Contact-Email");
    if (contactEmailNode != null) {
      final String contactEmail = contactEmailNode.asText();
      logger.debug(messages.getString("contact_email"), contactEmail);
      profile.setContactEmail(contactEmail);
    }
     final JsonNode contactPhoneNode = bagitProfileInfoNode.get("Contact-Phone");
    if (contactPhoneNode != null) {
      final String contactPhone = contactPhoneNode.asText();
      logger.debug(messages.getString("contact_phone"), contactPhone);
      profile.setContactPhone(contactPhone);
    }
}

Copy link
Author

@VolkerHartmann VolkerHartmann Nov 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If one of the required tags is not present, a NullPointerException is thrown.

final String profileIdentifier = bagitProfileInfoNode.get("BagIt-Profile-Identifier").asText();

See documentation of class BagLinter:

This class is only to be used on VALID bags, using it on un-validated bags may result in
exceptions being thrown (like {@link java.io.IOException} )

Therefore, no error handling is done anywhere in the code.

final String profileIdentifier = bagitProfileInfoNode.get("BagIt-Profile-Identifier").asText();
logger.debug(messages.getString("identifier"), profileIdentifier);
profile.setBagitProfileIdentifier(profileIdentifier);

final String sourceOrg = bagitProfileInfoNode.get("Source-Organization").asText();
logger.debug(messages.getString("source_organization"), sourceOrg);
profile.setSourceOrganization(sourceOrg);

final String contactName = bagitProfileInfoNode.get("Contact-Name").asText();
logger.debug(messages.getString("contact_name"), contactName);
profile.setContactName(contactName);

final String contactEmail = bagitProfileInfoNode.get("Contact-Email").asText();
logger.debug(messages.getString("contact_email"), contactEmail);
profile.setContactEmail(contactEmail);


final String extDescript = bagitProfileInfoNode.get("External-Description").asText();
logger.debug(messages.getString("external_description"), extDescript);
profile.setExternalDescription(extDescript);

final String version = bagitProfileInfoNode.get("Version").asText();
logger.debug(messages.getString("version"), version);
profile.setVersion(version);

final JsonNode contactNameNode = bagitProfileInfoNode.get("Contact-Name");
if (contactNameNode != null) {
final String contactName = contactNameNode.asText();
logger.debug(messages.getString("contact_name"), contactName);
profile.setContactName(contactName);
}

final JsonNode contactEmailNode = bagitProfileInfoNode.get("Contact-Email");
if (contactEmailNode != null) {
final String contactEmail = contactEmailNode.asText();
logger.debug(messages.getString("contact_email"), contactEmail);
profile.setContactEmail(contactEmail);
}

final JsonNode contactPhoneNode = bagitProfileInfoNode.get("Contact-Phone");
if (contactPhoneNode != null) {
final String contactPhone = contactPhoneNode.asText();
logger.debug(messages.getString("contact_phone"), contactPhone);
profile.setContactPhone(contactPhone);
}
}

@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private static Map<String, BagInfoRequirement> parseBagInfo(final JsonNode rootNode){
private static Map<String, BagInfoRequirement> parseBagInfo(final JsonNode rootNode) {
final JsonNode bagInfoNode = rootNode.get("Bag-Info");
logger.debug(messages.getString("parsing_bag_info"));
final Map<String, BagInfoRequirement> bagInfo = new HashMap<>();
final Map<String, BagInfoRequirement> bagInfo = new HashMap<>();

final Iterator<Entry<String, JsonNode>> nodes = bagInfoNode.fields(); //stuck in java 6...
while(nodes.hasNext()){

while (nodes.hasNext()) {
final Entry<String, JsonNode> node = nodes.next();

final BagInfoRequirement entry = new BagInfoRequirement();
entry.setRequired(node.getValue().get("required").asBoolean());

// due to specification required is false by default.
final JsonNode requiredNode = node.getValue().get("required");
if (requiredNode != null) {
entry.setRequired(requiredNode.asBoolean());
}

final JsonNode valuesNode = node.getValue().get("values");
if(valuesNode != null){
for(final JsonNode value : valuesNode){
if (valuesNode != null) {
for (final JsonNode value : valuesNode) {
entry.getAcceptableValues().add(value.asText());
}
}


final JsonNode repeatableNode = node.getValue().get("repeatable");
if (repeatableNode != null) {
entry.setRepeatable(repeatableNode.asBoolean());
}

logger.debug("{}: {}", node.getKey(), entry);
bagInfo.put(node.getKey(), entry);
}

return bagInfo;
}
private static List<String> parseManifestTypesRequired(final JsonNode node){

private static List<String> parseManifestTypesRequired(final JsonNode node) {
final JsonNode manifests = node.get("Manifests-Required");

final List<String> manifestTypes = new ArrayList<>();

for (final JsonNode manifestName : manifests) {
manifestTypes.add(manifestName.asText());
}

logger.debug(messages.getString("required_manifest_types"), manifestTypes);

return manifestTypes;
}
private static List<String> parseAcceptableSerializationFormats(final JsonNode node){

private static List<String> parseAcceptableSerializationFormats(final JsonNode node) {
final JsonNode serialiationFormats = node.get("Accept-Serialization");
final List<String> serialTypes = new ArrayList<>();

for (final JsonNode serialiationFormat : serialiationFormats) {
serialTypes.add(serialiationFormat.asText());
}
logger.debug(messages.getString("acceptable_serialization_mime_types"), serialTypes);

return serialTypes;
}
private static List<String> parseRequiredTagmanifestTypes(final JsonNode node){

private static List<String> parseRequiredTagmanifestTypes(final JsonNode node) {
final JsonNode tagManifestsRequiredNodes = node.get("Tag-Manifests-Required");
final List<String> requiredTagmanifestTypes = new ArrayList<>();

for(final JsonNode tagManifestsRequiredNode : tagManifestsRequiredNodes){
requiredTagmanifestTypes.add(tagManifestsRequiredNode.asText());
if (tagManifestsRequiredNodes != null) {
for (final JsonNode tagManifestsRequiredNode : tagManifestsRequiredNodes) {
requiredTagmanifestTypes.add(tagManifestsRequiredNode.asText());
}
}
logger.debug(messages.getString("required_tagmanifest_types"), requiredTagmanifestTypes);

return requiredTagmanifestTypes;
}
private static List<String> parseRequiredTagFiles(final JsonNode node){

private static List<String> parseRequiredTagFiles(final JsonNode node) {
final JsonNode tagFilesRequiredNodes = node.get("Tag-Files-Required");
final List<String> requiredTagFiles = new ArrayList<>();

for(final JsonNode tagFilesRequiredNode : tagFilesRequiredNodes){
requiredTagFiles.add(tagFilesRequiredNode.asText());

if (tagFilesRequiredNodes != null) {
for (final JsonNode tagFilesRequiredNode : tagFilesRequiredNodes) {
requiredTagFiles.add(tagFilesRequiredNode.asText());
}
}
logger.debug(messages.getString("tag_files_required"), requiredTagFiles);

return requiredTagFiles;
}
private static List<String> parseAcceptableVersions(final JsonNode node){

private static List<String> parseAcceptableVersions(final JsonNode node) {
final JsonNode acceptableVersionsNodes = node.get("Accept-BagIt-Version");
final List<String> acceptableVersions = new ArrayList<>();
for(final JsonNode acceptableVersionsNode : acceptableVersionsNodes){

for (final JsonNode acceptableVersionsNode : acceptableVersionsNodes) {
acceptableVersions.add(acceptableVersionsNode.asText());
}
logger.debug(messages.getString("acceptable_bagit_versions"), acceptableVersions);

return acceptableVersions;
}
}
1 change: 1 addition & 0 deletions src/main/resources/MessageBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ identifier=Identifier is [{}]
source_organization=Source-Organization is [{}]
contact_name=Contact-Name is [{}]
contact_email=Contact-Email is [{}]
contact_phone=Contact-Phone is [{}]
external_description=External-Description is [{}]
version=Version is [{}]
parsing_bag_info=Parsing the Bag-Info section
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/MessageBundle_ar.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ identifier=Identifier is [{}]
source_organization=Source-Organization is [{}]
contact_name=Contact-Name is [{}]
contact_email=Contact-Email is [{}]
contact_phone=Contact-Phone is [{}]
external_description=External-Description is [{}]
version=Version is [{}]
parsing_bag_info=Parsing the Bag-Info section
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/MessageBundle_de_DE.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ identifier=Identifier hat den Wert [{}]
source_organization=Source-Organization hat den Wert [{}]
contact_name=Contact-Name hat den Wert [{}]
contact_email=Contact-Email hat den Wert [{}]
contact_phone=Contact-Phone hat den Wert [{}]
external_description=External-Description hat den Wert [{}]
version=Version hat den Wert [{}]
parsing_bag_info=Lese Abschnitt Bag-Info
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/MessageBundle_es_ES.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ identifier=Identificador es [{}]
source_organization=Organizaci\u00f3n de la fuente es [{}]
contact_name=Nombre del contacto es [{}]
contact_email=Email del contacto es [{}]
contact_phone=Tel\u00e9fono de contacto es [{}]
external_description=Descripci\u00f3n externa es [{}]
version=La versi\u00f3n es [{}]
parsing_bag_info=An\u00e1lisis de la secci\u00f3n de la bag-info
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/MessageBundle_zh.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ identifier=Identifier is [{}]
source_organization=Source-Organization is [{}]
contact_name=Contact-Name is [{}]
contact_email=Contact-Email is [{}]
contact_phone=Contact-Phone is [{}]
external_description=External-Description is [{}]
version=Version is [{}]
parsing_bag_info=Parsing the Bag-Info section
Expand Down
Loading