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.
Join the DZone community and get the full member experience.
Join For FreeContent 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.
Opinions expressed by DZone contributors are their own.
Comments