Skip to content

Commit

Permalink
Update SLUB-INFO from repository
Browse files Browse the repository at this point in the history
Given the deposit does not contain a SLUB-INFO datastream but METS file
groups, use the SLUB-INFO datastream from the repository and update it
accordingly.

Given the deposit does contain a SLUB-INFO datastream, extend it with
attachment elements from the SLUB-INFO datastream of the repository.
  • Loading branch information
claussni committed Nov 26, 2015
1 parent 15d17bd commit 57515e4
Show file tree
Hide file tree
Showing 8 changed files with 372 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
import org.jdom.Namespace;

/**
* Represents a datastream that is about to be deleted.
* Whether the datastream is purged or it's state is set
* to 'DELETED' depends on the actual strategy carried out
* by a FileHandler that handles VoidDatastreams.
* Represents a datastream without content information.
* <p/>
* It's used to transport generic datastream properties to
* the FileHandler. Whether the datastream is purged or it's
* state is set to 'DELETED' depends on the actual strategy
* carried out by the FileHandler that handles VoidDatastreams.
*/
public class VoidDatastream extends Datastream {
public VoidDatastream(String id) {
super(id, State.DELETED, null, null);
super(id, null, null, null);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,29 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.purl.sword.server.fedora.fedoraObjects.State.DELETED;
import static org.purl.sword.server.fedora.fedoraObjects.State.INACTIVE;

public class METSContainer {

public static final Pattern PATTERN = Pattern.compile("^[a-z][a-z0-9\\+\\.\\-]*\\:.*", Pattern.CASE_INSENSITIVE);

public static final String DS_ID_SLUBINFO = "SLUB-INFO";
public static final String DS_ID_SLUBINFO_LABEL = "SLUB Administrative Metadata";
private static final String DS_ID_MODS = "MODS";
private static final String DS_ID_MODS_LABEL = "Object Bibliographic Metadata";
private static final String DS_ID_QUCOSAXML = "QUCOSA-XML";
private static final String DS_ID_QUCOSAXML_LABEL = "Pristine Qucosa XML Metadata";
private static final String DS_MODS_MIME_TYPE = "application/mods+xml";
private static final String DS_ID_MODS = "MODS";
private static final String DS_ID_MODS_LABEL = "Object Bibliographic Metadata";
private static final String METS_DMDSEC_PREFIX = "/mets:mets/mets:dmdSec";
private static final String MODS_PREFIX = METS_DMDSEC_PREFIX + "/mets:mdWrap[@MDTYPE='MODS']/mets:xmlData/mods:mods";

private final XPathQuery XPATH_FILES = new XPathQuery("/mets:mets/mets:fileSec/mets:fileGrp/mets:file");
private final XPathQuery XPATH_IDENTIFIERS = new XPathQuery(MODS_PREFIX + "/mods:identifier");
private final XPathQuery XPATH_MODS = new XPathQuery(MODS_PREFIX);
private final XPathQuery XPATH_QUCOSA = new XPathQuery(METS_DMDSEC_PREFIX + "/mets:mdWrap[@MDTYPE='OTHER' and @OTHERMDTYPE='QUCOSA-XML']/mets:xmlData/Opus");
private final XPathQuery XPATH_RELATEDITEMS = new XPathQuery(MODS_PREFIX + "/mods:relatedItem");
private final XPathQuery XPATH_SLUB = new XPathQuery("/mets:mets/mets:amdSec/mets:techMD" + "/mets:mdWrap[@MDTYPE='OTHER' and @OTHERMDTYPE='SLUBINFO']/mets:xmlData/slub:info");
private final XPathQuery XPATH_TITLE = new XPathQuery(MODS_PREFIX + "/mods:titleInfo/mods:title[1]");

private final String md5;
private final Document metsDocument;

Expand Down Expand Up @@ -125,15 +125,21 @@ public List<Datastream> getAugmentedFileDatastreams() throws SWORDException {
final String id = validateAndReturn("file ID", fileElement.getAttributeValue("ID"));

if (isADeleteRequest(fileElement)) {
datastreamList.add(new VoidDatastream(id));
final VoidDatastream voidDatastream = new VoidDatastream(id);
voidDatastream.setState(DELETED);
datastreamList.add(voidDatastream);
} else {
final Element fLocat = validateAndReturn("FLocat element", fileElement.getChild("FLocat", Namespaces.METS));
final String href = validateAndReturn("file content URL", fLocat.getAttributeValue("href", Namespaces.XLINK));
final URI uri = new URI(href);
final boolean isFile = uri.getScheme().equals("file");
final String mimetype = validateAndReturn("mime type", fileElement.getAttributeValue("MIMETYPE"));

Datastream ds = buildDatastream(id, fileElement, href, mimetype, isFile);
Datastream ds;
if (fileElement.getChild("FLocat", Namespaces.METS) != null) {
final Element fLocat = validateAndReturn("FLocat element", fileElement.getChild("FLocat", Namespaces.METS));
final String href = validateAndReturn("file content URL", fLocat.getAttributeValue("href", Namespaces.XLINK));
final URI uri = new URI(href);
final boolean isFile = uri.getScheme().equals("file");
final String mimetype = validateAndReturn("mime type", fileElement.getAttributeValue("MIMETYPE"));
ds = buildDatastream(id, fileElement, href, mimetype, isFile);
} else {
ds = new VoidDatastream(id);
}

String digestType = emptyIfNull(fileElement.getAttributeValue("CHECKSUMTYPE"));
String digest = emptyIfNull(fileElement.getAttributeValue("CHECKSUM"));
Expand Down Expand Up @@ -164,13 +170,15 @@ public List<File> getTemporayFiles() throws SWORDException {
fileElements = XPATH_FILES.selectNodes(metsDocument);
for (Element e : fileElements) {
if (!isADeleteRequest(e)) {
final Element fLocat = validateAndReturn("FLocat element", e.getChild("FLocat", Namespaces.METS));
final String href = validateAndReturn("file content URL", fLocat.getAttributeValue("href", Namespaces.XLINK));
final URI uri = new URI(href);
final boolean isFile = uri.getScheme().equals("file");
final boolean isTemporary = emptyIfNull(fLocat.getAttributeValue("USE")).equals("TEMPORARY");
if (isFile && isTemporary) {
filesMarkedForRemoval.add(new File(uri));
if (e.getChild("FLocat", Namespaces.METS) != null) {
final Element fLocat = validateAndReturn("FLocat element", e.getChild("FLocat", Namespaces.METS));
final String href = validateAndReturn("file content URL", fLocat.getAttributeValue("href", Namespaces.XLINK));
final URI uri = new URI(href);
final boolean isFile = uri.getScheme().equals("file");
final boolean isTemporary = emptyIfNull(fLocat.getAttributeValue("USE")).equals("TEMPORARY");
if (isFile && isTemporary) {
filesMarkedForRemoval.add(new File(uri));
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.jdom.Content;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
Expand Down Expand Up @@ -111,6 +112,8 @@ private void removeAugmentationWrapperFrom(List<Datastream> datastreams) {
* 5. To replace an existing datastream with a newer version a <mets:file> element has to be
* present, having an ID value equal to the DSID of an existing datastream.
* <p/>
* 6. Omit the <mets:FLocat> element to update USE attributes of a datastream without providing
* content.
* All datastream actions apply to the object PID specified in the deposit.
*
* @param deposit The deposit
Expand All @@ -131,22 +134,74 @@ public SWORDEntry updateDeposit(DepositCollection deposit, ServiceDocument servi
if (!deposit.isNoOp()) { // Don't ingest if no-op is set
update(repository, pid, fedoraObject.getDc());
final List<Datastream> datastreams = metsContainer.getDatastreams();

final XMLInlineDatastream repositorySlubInfo = (XMLInlineDatastream) repository.getDatastream(pid, METSContainer.DS_ID_SLUBINFO);
XMLInlineDatastream depositSlubInfo = (XMLInlineDatastream) findDatastream(METSContainer.DS_ID_SLUBINFO, datastreams);
if (repositorySlubInfo != null) {
if (depositSlubInfo == null) {
depositSlubInfo = repositorySlubInfo;
datastreams.add(repositorySlubInfo);
} else {
try {
mergeAttachmentElements(depositSlubInfo, repositorySlubInfo);
} catch (JDOMException e) {
throw new SWORDException("Cannot merge deposit SLUB-INFO with repository SLUB-INFO", e);
}
}
}

ensureAugmentedSlubInfoDatastream(datastreams);
removeAugmentationWrapperFrom(datastreams);

final List<Datastream> fileDatastreams = findDatastreams("ATT-", datastreams);
final Datastream slubInfoDatastream = findDatastream(METSContainer.DS_ID_SLUBINFO, datastreams);

updateIfPresent(repository, pid, metsContainer.getModsDatastream());
updateAttachmentDatastreams(repository, pid, fileDatastreams);
updateOrAdd(repository, pid, slubInfoDatastream);
updateOrAdd(repository, pid, depositSlubInfo);
updateOrAdd(repository, pid, metsContainer.getQucosaXmlDatastream());
delete(metsContainer.getTemporayFiles());
}

return swordEntry;
}

private void mergeAttachmentElements(XMLInlineDatastream into, XMLInlineDatastream from) throws JDOMException {
Element intoRights = into.toXML().getRootElement().getChild("rights", Namespaces.SLUB);

if (intoRights == null) {
intoRights = new Element("rights", Namespaces.SLUB);
into.toXML().getRootElement().addContent(intoRights);
}

final Element fromRights = from.toXML().getRootElement().getChild("rights", Namespaces.SLUB);

final Map<String, Element> fromAttachmentElementMap = getAttachmentElementMap(
(fromRights == null) ? null : XPATH_ATTACHMENTS.selectNodes(fromRights));

final Map<String, Element> intoAttachmentElementMap = getAttachmentElementMap(
(fromRights == null) ? null : XPATH_ATTACHMENTS.selectNodes(intoRights));

fromAttachmentElementMap.keySet().removeAll(intoAttachmentElementMap.keySet());

for (Element element : fromAttachmentElementMap.values()) {
intoRights.addContent((Content) element.clone());
}
}

private Map<String, Element> getAttachmentElementMap(final List<Element> fromList) {
return new HashMap<String, Element>() {{
CollectionUtils.forAllDo(
fromList,
new Closure() {
@Override
public void execute(Object input) {
Element item = (Element) input;
put(item.getAttributeValue("ref"), item);
}
});
}};
}

private METSContainer loadAndValidate(DepositCollection deposit) throws SWORDException {
validateDeposit(deposit);
METSContainer metsContainer = loadMets(deposit);
Expand Down Expand Up @@ -273,7 +328,7 @@ private boolean hasMd5(DepositCollection deposit) {
private void updateAttachmentDatastreams(FedoraRepository repository, String pid, List<Datastream> datastreams) throws SWORDException {
for (Datastream attDatastream : datastreams) {
if (attDatastream instanceof VoidDatastream) {
if (repository.hasDatastream(pid, attDatastream.getId())) {
if (repository.hasDatastream(pid, attDatastream.getId()) && DELETED.equals(attDatastream.getState())) {
repository.setDatastreamState(pid, attDatastream.getId(), DELETED, null);
}
} else {
Expand All @@ -298,12 +353,12 @@ private void update(FedoraRepository repository, String pid, Datastream datastre
}
}

private void updateOrAdd(FedoraRepository repository, String pid, Datastream datastream) throws SWORDException {
if (datastream != null) {
if (repository.hasDatastream(pid, datastream.getId())) {
repository.modifyDatastream(pid, datastream, null);
private void updateOrAdd(FedoraRepository repository, String pid, Datastream inputDatastream) throws SWORDException {
if (inputDatastream != null) {
if (repository.hasDatastream(pid, inputDatastream.getId())) {
repository.modifyDatastream(pid, inputDatastream, null);
} else {
repository.addDatastream(pid, datastream, null);
repository.addDatastream(pid, inputDatastream, null);
}
}
}
Expand All @@ -314,15 +369,15 @@ private void ensureAugmentedSlubInfoDatastream(List<Datastream> datastreams) thr

Document info;
Datastream slubInfo = findDatastream(METSContainer.DS_ID_SLUBINFO, datastreams);
if (slubInfo != null) {
info = ((XMLInlineDatastream) slubInfo).toXML();
} else {
if (slubInfo == null) {
info = new Document();
info.addContent(new Element("info", Namespaces.SLUB));
slubInfo = new XMLInlineDatastream(METSContainer.DS_ID_SLUBINFO, info);
slubInfo.setLabel(METSContainer.DS_ID_SLUBINFO_LABEL);
slubInfo.setVersionable(Boolean.parseBoolean(System.getProperty("datastream.versioning", "false")));
datastreams.add(slubInfo);
} else {
info = ((XMLInlineDatastream) slubInfo).toXML();
}

Element rights = info.getRootElement().getChild("rights", Namespaces.SLUB);
Expand All @@ -334,17 +389,7 @@ private void ensureAugmentedSlubInfoDatastream(List<Datastream> datastreams) thr
final List<Element> attachmentElements;
try {
attachmentElements = XPATH_ATTACHMENTS.selectNodes(rights);
Map<String, Element> attachmentElementMap = new HashMap<String, Element>() {{
CollectionUtils.forAllDo(
attachmentElements,
new Closure() {
@Override
public void execute(Object input) {
Element item = (Element) input;
put(item.getAttributeValue("ref"), item);
}
});
}};
Map<String, Element> attachmentElementMap = getAttachmentElementMap(attachmentElements);
for (Datastream attachmentDatastream : attachmentDatastreams) {
if (attachmentDatastream instanceof AugmentedDatastream) {
AugmentedDatastream augmentedDatastream = (AugmentedDatastream) attachmentDatastream;
Expand All @@ -357,7 +402,7 @@ public void execute(Object input) {
attachment.setAttribute("ref", attachmentDatastreamId);
attachment.setAttribute("hasArchivalValue", yesno(augmentedDatastream.isHasArchivalValue()));
attachment.setAttribute("isDownloadable", yesno(augmentedDatastream.isDownloadable()));
} else if (attachmentDatastream instanceof VoidDatastream) {
} else if ((attachmentDatastream instanceof VoidDatastream) && DELETED.equals(attachmentDatastream.getState())) {
rights.removeContent(
new XPathQuery("slub:attachment[@ref='" + attachmentDatastream.getId() + "']")
.selectNode(rights));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,25 @@ abstract class QucosaMETSFileHandler_AbstractTest {
));
}

public static final String MEDIA_TYPE = "application/vnd.qucosa.mets+xml";
public static final String COLLECTION = "collection:test";
public static final String USERNAME = "fedoraAdmin";
public static final String SUBMITTER = "qucosa";
public static final String METS_FILE_OK = "/mets_ok.xml";
public static final String METS_FILE_URL = "/mets_url_file.xml";
public static final String METS_FILE_BAD = "/mets_missing_mods.xml";
public static final String METS_FILE_BAD2 = "/mets_invalid_file.xml";
public static final String CONTENT_MODEL = "info:fedora/qucosa:CModel";
public static final String MEDIA_TYPE = "application/vnd.qucosa.mets+xml";
public static final String METS_FILE_ADD_DS = "/mets_add_ds.xml";
public static final String METS_FILE_ALLREFS = "/mets_all_references.xml";
public static final String METS_FILE_BAD = "/mets_missing_mods.xml";
public static final String METS_FILE_BAD2 = "/mets_invalid_file.xml";
public static final String METS_FILE_CHECKSUM = "/mets_file_checksum.xml";
public static final String METS_FILE_DELETE_DS = "/mets_delete_ds.xml";
public static final String METS_FILE_FILEGROUPS = "/mets_download_filegroup.xml";
public static final String METS_FILE_OK = "/mets_ok.xml";
public static final String METS_FILE_UPDATE = "/mets_update.xml";
public static final String METS_FILE_CHECKSUM = "/mets_file_checksum.xml";
public static final String METS_FILE_UPDATE_MD5 = "9a8d972d972eb799d989d0d2307c9822";
public static final String CONTENT_MODEL = "info:fedora/qucosa:CModel";
public static final String METS_FILE_URL = "/mets_url_file.xml";
public static final String METS_JUST_SLUBINFO = "/mets_just_slubinfo.xml";
public static final String METS_JUST_SLUBINFO_WITHOUT_RIGHTS = "/mets_just_slubinfo_without_rights.xml";
public static final String METS_NO_FLOCAT = "/mets_no_flocat.xml";
public static final String SUBMITTER = "qucosa";
public static final String USERNAME = "fedoraAdmin";

protected FedoraRepository mockFedoraRepository;
protected Appender mockAppender;
Expand Down
Loading

0 comments on commit 57515e4

Please sign in to comment.