Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Creating a Content Repository Using Jackrabbit Oak and MongoDB

DZone's Guide to

Creating a Content Repository Using Jackrabbit Oak and MongoDB

Let's start with some real code to see how we can create a repository with MongoDB. I will be using Maven to build the project and will use Java 8 for this example.

· Database Zone ·
Free Resource

Download the Altoros NoSQL Performance Benchmark 2018. Compare top NoSQL solutions – Couchbase Server v5.5, MongoDB v3.6, and DataStax Enterprise v6 (Cassandra).

Content repositories/content stores are essential in the digital world. A content repository/content store is a data store of digital content with an associated set of data management features.

Typically, content repositories act as the storage engine for larger applications such as a content management system or a document management system.

Java provides a content repository specification (JCR) that defines how to access content bi-directionally on a granular level within a content repository.

Apache Jackrabbit is the reference implementation of the Java Content Repository. Jackrabbit Oak is a part/flavor of Apache Jackrabbit that aims to provide a scalable and performant implementation of the Java Content Repository specification.

Oak supports multiple underlying storages for contents, like NoSQL, RDBMS, FS, etc. It also provides features like full-text search.

Oak Storage Flavors

Oak comes with two node storage flavors: segment and document.

Segment storage is optimized for max performance in standalone environments, whereas document storage is designed for scalability in clustered environments.

In this article, I will focus on the document storage flavor, which stores data in document-oriented format. The document store supports a number of backends, like MongoDocumentStore for MongoDB, RDBDocumentStore, and MemoryDocumentStore.

This article will cover MongoDocumentStore and explain how to manage content using Jackrabbit APIs and MongoDB as backend storage.

Now, let's start with some real code to see how we can create a repository with MongoDB. I will be using Maven to build the project and will use Java 8 for this example.

Maven Dependency

<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-jcr</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.3</version>
</dependency>

We need oak-jcr, jcr, and mongo-java-driver dependencies for using Jackrabbit libraries and connecting to MongoDB server.

Build/Initialize the Repository

The javax.jcr.Repository represents a content repository stored in MongoDB. The below code can be used to create a repository.

String uri = "mongodb://" + host + ":" + port;
DocumentNodeStore ns = new DocumentMK.Builder().setMongoDB(uri, "oak_demo", 16).getNodeStore();
Repository repo = new Jcr(new Oak(ns)).createRepository();

Here, oak_demo is the Mongo database to be connected.

Creating Nodes

Items or contents in node store are managed in nodes. Once we create the repository, we can use javax.jcr.Repository to log into the repository and get a javax.jcr.Session. The session is used to interact with the repository.

Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
Node parentNode = session.getRootNode();
Node childNode = parentNode.addNode("childNodeName");
childNode..setProperty("propertyName", "propertyValue");

Creating File Nodes

A File node is a different type of node than the normal node that we created in the above step. The type for the node we created earlier is "nt:unstructured:. The node type for file node is "nt:file". A File node is added to an existing node (at path /node1/node2).

Node fileNodeParent = session.getNode("pathToParentNode"); // /node1/node2/
Node fileNode = fileNodeParent.addNode("theFile", "nt:file");
Node content = fileNode.addNode("jcr:content", "nt:resource");
InputStream is = getFileInputStream();//Get the file data as stream.
Binary binary = session.getValueFactory().createBinary(is);
content.setProperty("jcr:data", binary);
session.save();
// To enable versioning use VersionManager
VersionManager vm = session.getWorkspace().getVersionManager();
vm.checkin(fileNode.getPath());

The File node needs to have a node of type nt:resource, which will store the file data as binary.

Retrieving File From Repository

Node fileNodeParent = session.getNode("pathToParentNode"); // /node1/node2/
Node fileContent = fileNodeParent.getNode("theFile").getNode("jcr:content");
Binary bin = fileContent.getProperty("jcr:data").getBinary();
InputStream stream = bin.getStream();
byte[] bytes = IOUtils.toByteArray(stream);
bin.dispose();
stream.close();

Retrieving Version of a Content

VersionManager vm = session.getWorkspace().getVersionManager();
javax.jcr.version.VersionHistory versionHistory = vm.getVersionHistory("filePath");
Version currentVersion = vm.getBaseVersion(filePath);// This is the current version of the file
VersionIterator itr = versionHistory.getAllVersions();// gets all the versions of that content

We can iterate over the VersionIterator to get specific versions and its properties.

Similarly, we can restore a specific version of a content.

//Restoring a specific version
VersionManager vm = session.getWorkspace().getVersionManager();
Version version = (Version) session.getNodeByIdentifier("versionId");
vm.restore(version, false);// boolean flag governs what happens in case of an identifier collision.

Likewise, other operations like deleting and editing files can be performed on content stored in the repository.

Conclusion

This is article covers basic steps to use the Jackrabbit Oak library with MongoDB. There are other features that Oak provides that are not covered in this article like indexing, searching documents, access control mechanisms, etc.

The complete example can be found in this GitHub repository.

Thanks for reading this article and please provide your opinions in the comment section.

Download the whitepaper, Moving From Relational to NoSQL: How to Get Started. We’ll take you step by step through your first NoSQL project.

Topics:
jackrabbit ,oak ,java content repository ,database ,mongodb ,tutorial ,data storage

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}