Skip to content

Commit

Permalink
added specs for extensions and updated changed the mutable head exten…
Browse files Browse the repository at this point in the history
…sion's extension name
  • Loading branch information
pwinckles committed Jan 25, 2021
1 parent b70e1b1 commit da0017f
Show file tree
Hide file tree
Showing 93 changed files with 14,679 additions and 37 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ new OCFL repositories, but is not required when opening an existing repository.
OCFL extension. Currently, the following extensions are implemented:
* [0002-flat-direct-storage-layout](https://ocfl.github.io/extensions/0002-flat-direct-storage-layout.html): `FlatLayoutConfig`
* [0003-hash-and-id-n-tuple-storage-layout](https://ocfl.github.io/extensions/0003-hash-and-id-n-tuple-storage-layout.html): `HashedNTupleIdEncapsulationLayoutConfig`
* [0004-hashed-n-tuple-storage-layout](https://github.com/OCFL/extensions/pull/16): `HashedNTupleLayoutConfig`
* [0004-hashed-n-tuple-storage-layout](https://ocfl.github.io/extensions/0004-hashed-n-tuple-storage-layout.html): `HashedNTupleLayoutConfig`

### Optional Properties

Expand Down Expand Up @@ -284,7 +284,7 @@ The following is a list of currently supported storage layout extensions:
* [0003-hash-and-id-n-tuple-storage-layout](https://ocfl.github.io/extensions/0003-hash-and-id-n-tuple-storage-layout.html)
* Configuration class: `HashedNTupleIdEncapsulationLayoutConfig`
* Implementation class: `HashedNTupleIdEncapsulationLayoutExtension`
* [0004-hashed-n-tuple-storage-layout](https://github.com/OCFL/extensions/pull/16)
* [0004-hashed-n-tuple-storage-layout](https://ocfl.github.io/extensions/0004-hashed-n-tuple-storage-layout.html)
* Configuration class: `HashedNTupleLayoutConfig`
* Implementation class: `HashedNTupleLayoutExtension`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private OcflConstants() {
public static final DigestAlgorithm DEFAULT_DIGEST_ALGORITHM = DigestAlgorithm.sha512;
public static final Set<DigestAlgorithm> ALLOWED_DIGEST_ALGORITHMS = Set.of(DigestAlgorithm.sha512, DigestAlgorithm.sha256);

public static final String MUTABLE_HEAD_EXT_PATH = EXTENSIONS_DIR + "/0004-mutable-head";
public static final String MUTABLE_HEAD_EXT_PATH = EXTENSIONS_DIR + "/0005-mutable-head";
public static final String MUTABLE_HEAD_VERSION_PATH = MUTABLE_HEAD_EXT_PATH + "/head";
public static final String MUTABLE_HEAD_REVISIONS_PATH = MUTABLE_HEAD_EXT_PATH + "/revisions";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -489,6 +490,7 @@ public void deletePath(String path) {
public void deleteObjects(Collection<String> objectPaths) {
if (!objectPaths.isEmpty()) {
var objectKeys = objectPaths.stream()
.filter(Objects::nonNull)
.map(keyBuilder::buildFromPath)
.collect(Collectors.toList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ public void basicMutableHeadTest(String repoPrefix) {
"inventory.json.sha512",
"v1/inventory.json",
"v1/inventory.json.sha512",
"extensions/0004-mutable-head/root-inventory.json.sha512",
"extensions/0004-mutable-head/revisions/r1",
"extensions/0004-mutable-head/head/inventory.json",
"extensions/0004-mutable-head/head/inventory.json.sha512",
"extensions/0004-mutable-head/head/content/r1/dir/file1.txt",
"extensions/0004-mutable-head/head/content/r1/dir/sub/file2.txt"
"extensions/0005-mutable-head/root-inventory.json.sha512",
"extensions/0005-mutable-head/revisions/r1",
"extensions/0005-mutable-head/head/inventory.json",
"extensions/0005-mutable-head/head/inventory.json.sha512",
"extensions/0005-mutable-head/head/content/r1/dir/file1.txt",
"extensions/0005-mutable-head/head/content/r1/dir/sub/file2.txt"
));

assertEquals("file1", streamToString(repo.getObject(ObjectVersionId.head(objectId)).getFile("dir/file1.txt").getStream()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
import edu.wisc.library.ocfl.core.util.DigestUtil;

/**
* Implementation of the Hashed Truncated N-tuple Trees for OCFL Storage Hierarchies extension.
*
* TODO add link to spec when finalized
* Implementation of the <a href="https://ocfl.github.io/extensions/0004-hashed-n-tuple-storage-layout.html">
* Hashed N-tuple Storage Layout</a> extension.
*/
public class HashedNTupleLayoutExtension implements OcflStorageLayoutExtension {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
import java.util.Objects;

/**
* Configuration for the Flat Storage Layout extension.
*
* TODO Add link to spec when finalized
* Configuration for the <a href="https://ocfl.github.io/extensions/0002-flat-direct-storage-layout.html">
* Flat Direct Storage Layout</a> extension.
*/
public class FlatLayoutConfig implements OcflExtensionConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@
import java.util.Objects;

/**
* Configuration for the Hashed Truncated N-tuple Trees for OCFL Storage Hierarchies extension.
*
* TODO Add link to spec when finalized
* Configuration for the <a href="https://ocfl.github.io/extensions/0004-hashed-n-tuple-storage-layout.html">
* Hashed N-tuple Storage Layout</a> extension.
*/
public class HashedNTupleLayoutConfig implements OcflExtensionConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public class CloudOcflStorageInitializer {

private static final Logger LOG = LoggerFactory.getLogger(CloudOcflStorageInitializer.class);

private static final String SPECS_DIR = "specs/";
private static final String MEDIA_TYPE_TEXT = "text/plain; charset=UTF-8";
private static final String MEDIA_TYPE_JSON = "application/json; charset=UTF-8";
private static final String OBJECT_MARKER_PREFIX = "0=ocfl_object";
Expand Down Expand Up @@ -209,6 +210,7 @@ private OcflStorageLayoutExtension initNewRepo(OcflVersion ocflVersion, OcflExte
keys.add(writeNamasteFile(ocflVersion));
keys.add(writeOcflSpec(ocflVersion));
keys.addAll(writeOcflLayout(layoutConfig, layoutExtension.getDescription()));
keys.add(writeOcflLayoutSpec(layoutConfig));
return layoutExtension;
} catch (RuntimeException e) {
LOG.error("Failed to initialize OCFL repository", e);
Expand All @@ -218,9 +220,21 @@ private OcflStorageLayoutExtension initNewRepo(OcflVersion ocflVersion, OcflExte
}

private String writeOcflSpec(OcflVersion ocflVersion) {
var ocflSpecFile = ocflVersion.getOcflVersion() + ".txt";
try (var ocflSpecStream = this.getClass().getClassLoader().getResourceAsStream(ocflSpecFile)) {
return uploadStream(ocflSpecFile, ocflSpecStream).getPath();
return writeSpecFile(ocflVersion.getOcflVersion() + ".txt");
}

private String writeOcflLayoutSpec(OcflExtensionConfig layoutConfig) {
try {
return writeSpecFile(layoutConfig.getExtensionName() + ".md");
} catch (RuntimeException e) {
LOG.warn("Failed to write spec file for layout extension {}", layoutConfig.getExtensionName(), e);
return null;
}
}

private String writeSpecFile(String fileName) {
try (var stream = this.getClass().getClassLoader().getResourceAsStream(SPECS_DIR + fileName)) {
return uploadStream(fileName, stream).getPath();
} catch (IOException e) {
throw new OcflIOException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class FileSystemOcflStorageInitializer {

private static final Logger LOG = LoggerFactory.getLogger(FileSystemOcflStorageInitializer.class);

private static final String SPECS_DIR = "specs/";
private static final String OBJECT_MARKER_PREFIX = "0=ocfl_object";

private final ObjectMapper objectMapper;
Expand Down Expand Up @@ -222,6 +223,7 @@ private OcflStorageLayoutExtension initNewRepo(Path repositoryRoot, OcflVersion
new NamasteTypeFile(ocflVersion.getOcflVersion()).writeFile(repositoryRoot);
writeOcflSpec(repositoryRoot, ocflVersion);
writeOcflLayout(repositoryRoot, layoutConfig, layoutExtension.getDescription());
writeOcflLayoutSpec(repositoryRoot, layoutConfig);
return layoutExtension;
} catch (RuntimeException e) {
LOG.error("Failed to initialize OCFL repository at {}", repositoryRoot, e);
Expand All @@ -232,8 +234,21 @@ private OcflStorageLayoutExtension initNewRepo(Path repositoryRoot, OcflVersion

private void writeOcflSpec(Path repositoryRoot, OcflVersion ocflVersion) {
var ocflSpecFile = ocflVersion.getOcflVersion() + ".txt";
try (var ocflSpecStream = this.getClass().getClassLoader().getResourceAsStream(ocflSpecFile)) {
Files.copy(ocflSpecStream, repositoryRoot.resolve(ocflSpecFile));
writeSpecFile(repositoryRoot, ocflSpecFile);
}

private void writeOcflLayoutSpec(Path repositoryRoot, OcflExtensionConfig layoutConfig) {
var specFile = layoutConfig.getExtensionName() + ".md";
try {
writeSpecFile(repositoryRoot, specFile);
} catch (RuntimeException e) {
LOG.warn("Failed to write spec file for layout extension {}", layoutConfig.getExtensionName(), e);
}
}

private void writeSpecFile(Path repositoryRoot, String fileName) {
try (var stream = this.getClass().getClassLoader().getResourceAsStream(SPECS_DIR + fileName)) {
Files.copy(stream, repositoryRoot.resolve(fileName));
} catch (IOException e) {
throw new OcflIOException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# OCFL Community Extension 0002: Flat Direct Storage Layout

* **Extension Name:** 0002-flat-direct-storage-layout
* **Authors:** Peter Winckles
* **Minimum OCFL Version:** 1.0
* **OCFL Community Extensions Version:** 1.0
* **Obsoletes:** n/a
* **Obsoleted by:** n/a

## Overview

This storage root extension describes a simple flat OCFL storage layout. OCFL object identifiers are mapped directly to directory names that are direct children of the OCFL storage root directory.

The limitations of this layout are filesystem dependent, but are generally as follows:

* The size of object IDs cannot exceed the maximum allowed directory name size (eg. 255 characters)
* Object IDs cannot include characters that are illegal in directory names
* Performance may degrade as the size of a repository increases because every object is a direct child of the storage root

## Parameters

This extension has no parameters.

## Procedure

The OCFL object identifier is used, without any changes, as the object's root path within the OCFL storage root.

## Examples

### Example 1

This example demonstrates some mappings that produce directory names that are valid on unix filesystems.

#### Mappings

| Object ID | Object Root Path |
| --- | --- |
| object-01 | `object-01` |
| ..hor\_rib:lé-$id | `..hor_rib:lé-$id` |

#### Storage Hierarchy

```
[storage_root]/
├── 0=ocfl_1.0
├── ocfl_layout.json
├── object-01/
│ ├── 0=ocfl_object_1.0
│ ├── inventory.json
│ ├── inventory.json.sha512
│ └── v1 [...]
└── ..hor_rib:lé-$id/
├── 0=ocfl_object_1.0
├── inventory.json
├── inventory.json.sha512
└── v1 [...]
```

### Example 2

This example demonstrates some mappings that produce directory names that are invalid on unix filesystems; therefore this layout cannot be used in a repository that needs to be able to store objects with IDs like these.

#### Mappings

| Object ID | Object Root Path |
| --- | --- |
| info:fedora/object-01 | `info:fedora/object-01` |
| abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij | `abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij` |

Loading

0 comments on commit da0017f

Please sign in to comment.