package gov.loc.repository.bagit.conformance.profile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
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;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
/**
* 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");
public BagitProfileDeserializer() {
this(null);
}
public BagitProfileDeserializer(final Class<?> vc) {
super(vc);
}
@Override
public BagitProfile deserialize(final JsonParser p, final DeserializationContext ctxt)
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());
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){
final JsonNode bagitProfileInfoNode = node.get("BagIt-Profile-Info");
logger.debug(messages.getString("parsing_bagit_profile_info_section"));
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);
}
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
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 Iterator<Entry<String, JsonNode>> nodes = bagInfoNode.fields(); //stuck in java 6...
while(nodes.hasNext()){
final Entry<String, JsonNode> node = nodes.next();
final BagInfoRequirement entry = new BagInfoRequirement();
entry.setRequired(node.getValue().get("required").asBoolean());
final JsonNode valuesNode = node.getValue().get("values");
if(valuesNode != null){
for(final JsonNode value : valuesNode){
entry.getAcceptableValues().add(value.asText());
}
}
logger.debug("{}: {}", node.getKey(), entry);
bagInfo.put(node.getKey(), entry);
}
return bagInfo;
}
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){
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){
final JsonNode tagManifestsRequiredNodes = node.get("Tag-Manifests-Required");
final List<String> requiredTagmanifestTypes = new ArrayList<>();
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){
final JsonNode tagFilesRequiredNodes = node.get("Tag-Files-Required");
final List<String> requiredTagFiles = new ArrayList<>();
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){
final JsonNode acceptableVersionsNodes = node.get("Accept-BagIt-Version");
final List<String> acceptableVersions = new ArrayList<>();
for(final JsonNode acceptableVersionsNode : acceptableVersionsNodes){
acceptableVersions.add(acceptableVersionsNode.asText());
}
logger.debug(messages.getString("acceptable_bagit_versions"), acceptableVersions);
return acceptableVersions;
}
}