Skip to content

Commit

Permalink
Make display ocfl path configurable and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
whikloj committed May 25, 2024
1 parent 5370495 commit 5f7f969
Show file tree
Hide file tree
Showing 5 changed files with 323 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree.
*/
package org.fcrepo.config;

/**
* Display OCFL path mode enum
* @author whikloj
*/
public enum DisplayOcflPath {
NONE("none"),
RELATIVE("relative"),
ABSOLUTE("absolute");

private final String value;

DisplayOcflPath(final String value) {
this.value = value;
}

public String getValue() {
return value;
}

public static DisplayOcflPath fromString(final String value) {
for (final var mode : values()) {
if (mode.value.equalsIgnoreCase(value)) {
return mode;
}
}
throw new IllegalArgumentException("Unknown display OCFL path mode: " + value);
}

@Override
public String toString() {
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class OcflPropsConfig extends BasePropsConfig {
public static final String FCREPO_OCFL_ROOT = "fcrepo.ocfl.root";
public static final String FCREPO_OCFL_TEMP = "fcrepo.ocfl.temp";
private static final String FCREPO_OCFL_S3_BUCKET = "fcrepo.ocfl.s3.bucket";
private static final String FCREPO_OCFL_SHOW_PATH = "fcrepo.ocfl.display_path";

private static final String OCFL_STAGING = "staging";
private static final String OCFL_ROOT = "ocfl-root";
Expand Down Expand Up @@ -120,6 +121,10 @@ public class OcflPropsConfig extends BasePropsConfig {
@Value("${fcrepo.ocfl.verify.inventory:true}")
private boolean verifyInventory;

@Value("${" + FCREPO_OCFL_SHOW_PATH + ":none}")
private String displayOcflPathStr;
private DisplayOcflPath displayOcflPath;

private DigestAlgorithm FCREPO_DIGEST_ALGORITHM;

/**
Expand Down Expand Up @@ -172,6 +177,8 @@ private void postConstruct() throws IOException {
.collect(Collectors.joining(", "))));
}
LOGGER.info("Fedora OCFL digest algorithm: {}", FCREPO_DIGEST_ALGORITHM.getAlgorithm());
displayOcflPath = DisplayOcflPath.fromString(displayOcflPathStr);
LOGGER.info("Fedora OCFL display path: {}", displayOcflPath.getValue());
}

/**
Expand Down Expand Up @@ -496,4 +503,18 @@ public boolean isOcflUpgradeOnWrite() {
public boolean verifyInventory() {
return verifyInventory;
}

/**
* @param displayOcflPath the display OCFL path mode
*/
public void setDisplayOcflPath(final String displayOcflPath) {
this.displayOcflPath = DisplayOcflPath.fromString(displayOcflPath);
}

/**
* @return the display OCFL path mode
*/
public DisplayOcflPath getDisplayOcflPath() {
return displayOcflPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public final class RdfLexicon {
createProperty(REPOSITORY_NAMESPACE + "lastModified");
public static final Property LAST_MODIFIED_BY =
createProperty(REPOSITORY_NAMESPACE + "lastModifiedBy");
public static final Property FEDORA_OCFL_PATH =
createProperty(REPOSITORY_NAMESPACE + "ocflPath");

public static final Resource FEDORA_CONTAINER =
createResource(REPOSITORY_NAMESPACE + "Container");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
import static org.apache.jena.vocabulary.RDF.type;
import static org.fcrepo.kernel.api.RdfLexicon.CREATED_BY;
import static org.fcrepo.kernel.api.RdfLexicon.CREATED_DATE;
import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_OCFL_PATH;
import static org.fcrepo.kernel.api.RdfLexicon.HAS_MESSAGE_DIGEST;
import static org.fcrepo.kernel.api.RdfLexicon.HAS_MIME_TYPE;
import static org.fcrepo.kernel.api.RdfLexicon.HAS_ORIGINAL_NAME;
import static org.fcrepo.kernel.api.RdfLexicon.HAS_SIZE;
import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_BY;
import static org.fcrepo.kernel.api.RdfLexicon.LAST_MODIFIED_DATE;
import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
import static org.slf4j.LoggerFactory.getLogger;

import static java.nio.charset.StandardCharsets.UTF_8;
Expand All @@ -33,6 +33,7 @@
import java.util.stream.Stream;

import org.apache.jena.graph.Triple;
import org.fcrepo.config.DisplayOcflPath;
import org.fcrepo.config.OcflPropsConfig;
import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
import org.fcrepo.kernel.api.identifiers.FedoraId;
Expand Down Expand Up @@ -119,9 +120,11 @@ public Stream<Triple> get(final FedoraResource resource) {
triples.add(Triple.create(subject, type.asNode(), createURI(triple.toString())));
});

final var ocflPath = resolveOcflPath(describedResource);
triples.add(Triple.create(subject, createURI(REPOSITORY_NAMESPACE + "ocflPath"),
createLiteral(ocflPath)));
if (ocflPropsConfig.getDisplayOcflPath() != DisplayOcflPath.NONE) {
final var ocflPath = resolveOcflPath(describedResource, ocflPropsConfig.getDisplayOcflPath());
triples.add(Triple.create(subject, createURI(FEDORA_OCFL_PATH.getURI()),
createLiteral(ocflPath)));
}

return new DefaultRdfStream(subject, triples.stream());
}
Expand All @@ -133,7 +136,7 @@ private String resolveId(final FedoraResource resource) {
return resource.getId();
}

private String resolveOcflPath(final FedoraResource resource) {
private String resolveOcflPath(final FedoraResource resource, final DisplayOcflPath displayOcflPath) {
try {
final FedoraId id;
if (resource.getArchivalGroupId().isPresent()) {
Expand All @@ -144,8 +147,14 @@ private String resolveOcflPath(final FedoraResource resource) {
final var algo = MessageDigest.getInstance("sha-256");
final var ocflId = algo.digest(id.getBaseId().getBytes(UTF_8));
final var ocflIdHash = encodeHexString(ocflId);
return ocflPropsConfig.getOcflRepoRoot() + "/" + ocflIdHash.substring(0, 3) + "/" +
ocflIdHash.substring(3, 6) + "/" + ocflIdHash.substring(6, 9) + "/" + ocflIdHash;
final List<String> hashSlices = new ArrayList<>();
for (int i = 0; i < ocflIdHash.length(); i += 3) {
hashSlices.add(ocflIdHash.substring(i, Math.min(i + 3,ocflIdHash.length())));
}
final var ocflPath = hashSlices.get(0) + "/" + hashSlices.get(1) + "/" + hashSlices.get(2) + "/" +
ocflIdHash;
return (displayOcflPath == DisplayOcflPath.ABSOLUTE ? ocflPropsConfig.getOcflRepoRoot() + "/" : "") +
ocflPath;
} catch (NoSuchAlgorithmException e) {
final var message = "Unable to resolve OCFL path for resource " + resource.getId();
LOGGER.error(message, e);
Expand Down
Loading

0 comments on commit 5f7f969

Please sign in to comment.