About JCR – Java Content Repository
JCR, also known as Java Content Repository or Content Repository for Java Technology API, actually consists of two specifications: JSR-170 describing JCR 1.0 and JSR-283 describing JCR 2.0. Both standards are intended to access content repositories in an uniform manner. First, it was developed by Day Software, but then partially given to the Apache Software Foundation (ASF). JCR is developing under the Java Community Process (JCP). You can find its componentes within the Java package javax.jcr.
Introduction to JCR
JCR is an API for accessing content repositories. Like Hibernate ORM, JCR is not bound to any specific storage format or technology vendor. It can be used with RDBMSs, object oriented databases or plain XML.
A content repository stores data hierarchically. JCRs repository model consists of workspaces in the first layer. Each workspace contains a tree of items, beginning with one root node. An item is either a node or a property. Any node can have zero or more child nodes and zero or more properties. Each node, except the root node, must have a parent node. Each property has a parent node.
As a content repository uses a hierarchical model, any item can be accessed by an absolute path, i.e. a premium car could be stored under the path “/car/premium/mercedes”. Those paths are similar to the UNIX style paths. So even “.” and “..” can be used to navigate relatively through the repository.
Hands on
The following fragment shows, how to connect to a content repository via JNDI using JCR after it is bound to the containers context and is up and running.
// Lookup the repository using JNDI
InitialContext ctx = ...
Repository repository = (Repository)ctx.lookup("java:comp/env/myrepository");
// Create credentials
Credentials credentials = new SimpleCredentials("repouser", "letmein".toCharArray());
// Get a Session using the credentials und the "default"-workspace
Session mySession = repository.login(credentials, "default");
The following class shows how to traversally access the repository.
package de.mhsdev.jcr.client;
import java.net.MalformedURLException;
import javax.jcr.Credentials;
import javax.jcr.LoginException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Value;
import javax.naming.NamingException;
import org.apache.jackrabbit.rmi.repository.URLRemoteRepository;
/**
* Traverses the given repository and prints nodes and properties under the
* given path.
*
* @author mhavers
*
*/
public class JCRClient {
/**
* @param args
* @throws NamingException
* @throws RepositoryException
* @throws NoSuchWorkspaceException
* @throws LoginException
* @throws MalformedURLException
*/
public static void main(String[] args) throws NamingException,
LoginException, NoSuchWorkspaceException, RepositoryException,
MalformedURLException {
// Get the Repository object
Repository repository = new URLRemoteRepository(
"http://localhost:8081/rmi");
// Get a Credentials object
Credentials credentials = new SimpleCredentials("repouser", "repouser"
.toCharArray());
// Get a Session
Session mySession = repository.login(credentials, "default");
// Output
printTraversal(mySession.getNode("/"), "");
}
private static void printTraversal(Node node, String proposition)
throws RepositoryException {
System.out.print(node.getPath());
printProperties(node);
System.out.println("");
NodeIterator nodeIt = node.getNodes();
while (nodeIt.hasNext()) {
printTraversal(nodeIt.nextNode(), proposition + "+ ");
}
}
private static void printProperties(Node node) throws RepositoryException {
System.out.println(" {");
PropertyIterator propIt = node.getProperties();
while (propIt.hasNext()) {
Property prop = propIt.nextProperty();
if (prop.isMultiple()) {
System.out.print("+ " + prop.getName() + " [ ");
for (Value value : prop.getValues()) {
System.out.print(value + " ");
}
System.out.print("]");
System.out.println();
} else {
System.out.println("+ " + prop.getName() + "="
+ prop.getValue());
}
}
System.out.println("}");
}
}
Depending on your repositories content, the output may i.e. be…
/ {
+ jcr:primaryType=rep:root
}
/jcr:system {
+ jcr:primaryType=rep:system
}
/jcr:system/jcr:versionStorage {
+ jcr:primaryType=rep:versionStorage
}
/jcr:system/jcr:activities {
+ jcr:primaryType=rep:Activities
}
/jcr:system/jcr:nodeTypes {
+ jcr:primaryType=rep:nodeTypes
}
/jcr:system/jcr:nodeTypes/rep:Group {
+ jcr:hasOrderableChildNodes=false
+ jcr:isMixin=false
+ jcr:nodeTypeName=rep:Group
+ jcr:mixinTypes [ ]
+ jcr:supertypes [ rep:Authorizable ]
+ jcr:primaryType=nt:nodeType
}
/jcr:system/jcr:nodeTypes/rep:Group/jcr:propertyDefinition {
+ jcr:requiredType=WEAKREFERENCE
+ jcr:autoCreated=false
+ jcr:multiple=true
+ jcr:mixinTypes [ ]
+ jcr:protected=true
+ jcr:name=rep:members
+ jcr:mandatory=false
+ jcr:valueConstraints [ {internal}Authorizable ]
+ jcr:primaryType=nt:propertyDefinition
+ jcr:onParentVersion=COPY
}
…
Accessing the repository directly via a given path is as easy as traversing. Just invoke the i.e. getItem(String) method on the session object and parametrize it with an absolute path.
Property myProperty = (Property)mySession.getItem("/jcr:system/jcr:nodeTypes/rep:Group");
Even writing is made easy.
// Retrieve a node
Node myNode = (Node) mySession.getItem("/car/premium/mercedes");
// Add a child node
Node newNode = myNode.addNode("C Class");
// Add a property
newNode.setProperty("model", "C250 CDI");
// Persist the changes
mySession.save();
Implementations
The Apache Software Foundation develops the JSR-170 and JSR-283 reference implementation (JCR-RI) as open source under the roof of the Apache Jackrabbit project.
A commercial but very powerful implementation is supplied by Day Software. Days implementation is called Content Repository Extreme (CRX) and brings enterprise level features like an easy to use web UI, and enhanced administrative tools and technologies with it.
Supporting Tools
- JCR-Explorer, a web based user interface to browse and modify content repositories shared within the current container using JNDI
- JCR-Browser, an eclipse plugin for browsing content repositories (supports RMI, JNDI and HTTP connections)
References and resources
- JSR-170
- JSR-283
- JCR from Day Software
- Apache Jackrabbit
- Wikipedia explanation of JCR
- Introduction to Java Content Repository API by IBM
- Catch Jackrabbit and the Java Content Repository API
- What is Java Content Repository
- Planet Day
