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 Free
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,
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.
<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>
mongo-java-driver dependencies for using Jackrabbit libraries and connecting to MongoDB server.
Build/Initialize the Repository
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();
oak_demo is the Mongo database to be connected.
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
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.
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.