Skip to content
A Java OCFL implementation (WIP)
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
pom.xml restricted the content-addressing digest algorithm to sha512 and sha2… Oct 4, 2019


This project is a Java implementation of the OCFL beta 0.3 spec.

Build Status

Requirements and Installation

ocfl-java is a Java 11 project and at the minimum requires Java 11 to run.

The ocfl-java libraries are not yet being built to a public Maven repository. Until they are, you'll need to build the libraries locally as follows:

$ git clone
$ cd ocfl-java
$ mvn install

After building the libraries locally, add the following to you're project's POM:


Example Usage

var repoDir = Paths.get("ocfl-repo");

var repo = new OcflRepositoryBuilder().build(
        new FileSystemOcflStorage(repoDir, new ObjectIdPathMapperBuilder().

repo.putObject(ObjectId.head("o1"), Paths.get("object-out-dir"), new CommitInfo().setMessage("initial commit"));
repo.getObject(ObjectId.head("o1"), Paths.get("object-in-dir"));

repo.updateObject(ObjectId.head("o1"), new CommitInfo().setMessage("update"), updater -> {
    updater.addPath(Paths.get("path-to-file2"), "file2")
            .addPath(Paths.get("path-to-file3"), "dir1/file3");

repo.readObject(ObjectId.version("o1", "v1"), reader -> {
    reader.getFile("path", Paths.get("destination"));

Extension Points

ocfl-java-core provides the core framework an OCFL repository, and exposes a number of extension points for configuring its behavior and storage layer. The core implementation class is edu.wisc.library.ocfl.core.DefaultOcflRepository.


Storage layer implementations must implement edu.wisc.library.ocfl.core.OcflStorage. There are the following existing implementations:

  • FileSystemOcflStorage: Basic implementation that stores all objects within a single root on the local filesystem.

Object ID Mapping

Object IDs must be mapped to paths relative to the OCFL root. The OCFL spec does not define specifically how this should be done. Out of the box, ocfl-java supports three different mapping algorithms, and additional implementations can be defined by implementing edu.wisc.library.oclf.core.mapping.ObjectIdPathMapper.

  • FlatObjectIdPathMapper: Encodes object IDs using UrlEncoder or PairTreeEncoder. The encoded ID is used to create an object root as a direct child of the OCFL root. This is the simplest mapper, but has serious performance problems and should generally be avoided.
  • PairTreeObjectIdPathMapper: This is an implementation the pairtree spec. It sports much better performance than FlatObjectIdPathMapper. It's draw back is that it produces deep, unbalanced trees.
  • HashingObjectIdPathMapper: Similar to PairTreeObjectIdPathMapper except that object IDs are hashed and the depth is truncated. This is the most performant option because the file tree is shallow and balanced. It's disadvantage, compared to PairTreeObjectIdPathMapper, is that directory names are not reversible to object IDs.
  • CachingObjectIdPathMapper: This mapper can be used to wrap any ObjectIdPathMapper and cache its results.


A lock is used to guard against concurrent object edits. Custom lock implementations can be defined by implementing edu.wisc.library.ocfl.core.lock.ObjectLock. The following implementations are provided:

  • InMemoryObjectLock: Simple in-memory lock implementation that's based on Java's ReentrantReadWriteLock. This implementation is suitable when a single application is operating on an OCFL repository.


A cache is used so that an object's inventory does not need to parsed on every request. Custom cache implementations should implement edu.wisc.library.ocfl.core.cache.Cache. The following implementations are provided:

  • NoOpCache: Use this if you never want to cache anything.
  • CaffeineCache: In-memory cache that uses Caffeine.
You can’t perform that action at this time.