First Steps
Please refer to the README.txt
to find details on how to build Jackrabbit using Maven.
The following code provides a brief introduction to using Jackrabbit
in a simple application. Please note that this example is meant to
be as short and simple as possible, rather than usable as a real
application, and should not be interpreted as best practice.
JCRTest.java
import java.util.Hashtable;
import javax.jcr.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.jackrabbit.core.jndi.RegistryHelper;
public class JCRTest {
public static void main(String[] args) {
try {
String configFile = "repotest/repository.xml ";
String repHomeDir = "repotest ";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
env.put(Context.PROVIDER_URL, "localhost");
InitialContext ctx = new InitialContext(env);
RegistryHelper.registerRepository(ctx, "repo", configFile, repHomeDir, true);
Repository r = (Repository) ctx.lookup("repo");
Session session = r.login(new SimpleCredentials("userid", "".toCharArray()), null);
Node rn=session.getRootNode();
System.out.println(rn.getPrimaryNodeType().getName());
} catch (Exception e){
System.err.println(e);
}
}
}
The configFile
variable points to a file, named
repository.xml
by convention, that contains
the repository configuration.
An example repository.xml
might look like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${rep.home}/repository"/>
</FileSystem>
<Security appName="Jackrabbit">
<AccessManager class="org.apache.jackrabbit.core.security.SimpleAccessManager"/>
</Security>
<Workspaces rootPath="${rep.home}/workspaces" defaultWorkspace="default" />
<Workspace name="${wsp.name}">
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${wsp.home}"/>
</FileSystem>
<PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager" />
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${wsp.home}/index"/>
</FileSystem>
</SearchIndex>
</Workspace>
<Versioning rootPath="${rep.home}/versions">
<FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${rep.home}/versions"/>
</FileSystem>
<PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager" />
</Versioning>
</Repository>
The keyword ${rep.home}
refers to the repository home
directory, which is used as the root directory for all of the
information that the repository persists. The directory can be
empty; after initial startup, the repository will be filled with
file structure similar to this:
repository.xml
repository/
meta/
namespaces/
nodetypes/
versions/
tx/
workspaces/
default/
workspace.xml
blobs/
data/
index/
In addition to the repository configuration file, you also need to
create a
JAAS configuration
file used for Jackrabbit login settings. The contents of a simple
configuration file named jaas.config
is shown below. The
configuration for the SimpleLoginModule also contains an optional module
option to configure the user id of the anonymous user with read-only access
to the repository. If the option is omitted the anoymous user id default to
'anonymous'.
Jackrabbit {
org.apache.jackrabbit.core.security.SimpleLoginModule required anonymousId="anonymous";
};
Make sure that all of the dependencies
are added to your classpath, as well as the Jackrabbit
repository implementation (named something like
jackrabbit-x.xx-xxx-dev.jar
) that has been built by Maven
into the target
directory of your checkout.
By executing maven copy-deps
all dependencies except
the optional runtime cqfs-*
libaries are
being copied to the target/lib
directory. I addition
to setting up the classpath, you need to include the JAAS configuration
option -Djava.security.auth.login.config==jaas.config
(note the double equal sign ==
) to the java
command when running the example code.
Now you should be ready to compile the above JCRTest
class and run it, which should produce the following output:
rep:root
Since an empty repository is not very useful, add the following
code to the above test class JCRTest
to create
content inside Jackrabbit.
JCRTest.java
import java.util.Hashtable;
import javax.jcr.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.jackrabbit.core.jndi.RegistryHelper;
public class JCRTest {
public static void main(String[] args) {
try {
String configFile = "repotest/repository.xml";
String repHomeDir = "repotest";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
env.put(Context.PROVIDER_URL, "localhost");
InitialContext ctx = new InitialContext(env);
RegistryHelper.registerRepository(ctx, "repo", configFile, repHomeDir, true);
Repository r = (Repository) ctx.lookup("repo");
Session session = r.login(new SimpleCredentials("userid", "".toCharArray()), null);
Node rn=session.getRootNode();
System.out.println(rn.getPrimaryNodeType().getName());
if (!rn.hasNode("testnode")) {
System.out.println("creating testnode");
Node n=rn.addNode("testnode", "nt:unstructured");
n.setProperty("testprop", new StringValue("Hello, World."));
session.save();
}
System.out.println(rn.getProperty("testnode/testprop").getString());
} catch (Exception e){
System.err.println(e);
}
}
}
which should produce the following output (possibly surrounded by log
messages, depending on settings) when started for the first time:
rep:root
creating testnode
Hello, World.
To add content a bit more efficiently, you may want to try
JCR's import facilities, such as Session.importXML
.
The following XML document by Elliotte Rusty Harold
provides an interesting example that demonstrates a repository's
namespace capabilities:
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:mathml="http://www.w3.org/1998/Math/MathML">
<xhtml:head><xhtml:title>Three Namespaces</xhtml:title></xhtml:head>
<xhtml:body>
<xhtml:h1 align="center">An Ellipse and a Rectangle</xhtml:h1>
<svg:svg xmlns:svg="http://www.w3.org/2000/svg"
width="12cm" height="10cm">
<svg:ellipse rx="110" ry="130" />
<svg:rect x="4cm" y="1cm" width="3cm" height="6cm" />
</svg:svg>
<xhtml:p>The equation for ellipses</xhtml:p>
<mathml:math>
<mathml:apply>
<mathml:eq/>
<mathml:cn> 1 </mathml:cn>
<mathml:apply>
<mathml:plus/>
<mathml:apply>
<mathml:divide/>
<mathml:apply>
<mathml:power/>
<mathml:ci> x </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
<mathml:apply>
<mathml:power/>
<mathml:ci> a </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
</mathml:apply>
<mathml:apply>
<mathml:divide/>
<mathml:apply>
<mathml:power/>
<mathml:ci> y </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
<mathml:apply>
<mathml:power/>
<mathml:ci> b </mathml:ci>
<mathml:cn> 2 </mathml:cn>
</mathml:apply>
</mathml:apply>
</mathml:apply>
</mathml:apply>
</mathml:math>
<xhtml:hr/>
<xhtml:p>Last Modified January 10, 2002</xhtml:p>
</xhtml:body>
</xhtml:html>
The JCRTest
class is then extended with
Session.importXml()
to import the XML file named
repotest/test.xml
, and a simple dump()
method is added to display the content of the repository.
import java.io.FileInputStream;
import java.util.Hashtable;
import javax.jcr.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.apache.jackrabbit.core.jndi.RegistryHelper;
public class JCRTest {
public static void main(String[] args) {
try {
String configFile = "repotest/repository.xml";
String repHomeDir = "repotest";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
env.put(Context.PROVIDER_URL, "localhost");
InitialContext ctx = new InitialContext(env);
RegistryHelper.registerRepository(ctx, "repo", configFile, repHomeDir, true);
Repository r = (Repository) ctx.lookup("repo");
Session session = r.login(new SimpleCredentials("userid", "".toCharArray()), null);
Node rn=session.getRootNode();
System.out.println(rn.getPrimaryNodeType().getName());
if (!rn.hasNode("testnode")) {
System.out.println("creating testnode");
Node n=rn.addNode("testnode", "nt:unstructured");
n.setProperty("testprop", new StringValue("Hello, World."));
session.save();
}
if (!rn.hasNode("importxml")) {
System.out.println("importing xml");
Node n=rn.addNode("importxml", "nt:unstructured");
session.importXML("/importxml", new FileInputStream("repotest/test.xml "));
session.save();
}
dump(rn);
} catch (Exception e){
System.err.println(e);
}
}
public static void dump (Node n) throws RepositoryException {
System.out.println(n.getPath());
PropertyIterator pit=n.getProperties();
while (pit.hasNext()) {
Property p=pit.nextProperty();
System.out.print(p.getPath() + "=");
if (p.getDefinition().isMultiple()) {
Value[] values = p.getValues();
for (int i = 0; i < values.length; i++) {
if (i > 0) System.out.println(",");
System.out.println(values[i].getString());
}
} else {
System.out.print(p.getString());
}
System.out.println();
}
NodeIterator nit=n.getNodes();
while (nit.hasNext()) {
Node cn=nit.nextNode();
dump (cn);
}
}
}
Which should output something along the lines of:
rep:root
/
/jcr:primaryType=rep:root
/jcr:system
/jcr:system/jcr:primaryType=rep:system
/jcr:system/jcr:versionStorage
/jcr:system/jcr:versionStorage/jcr:primaryType=rep:versionStorage
/jcr:system/jcr:versionStorage/jcr:mixinTypes=
/testnode
/testnode/jcr:primaryType=nt:unstructured
/testnode/testprop=Hello, World.
/importxml
/importxml/jcr:primaryType=nt:unstructured
/importxml/xhtml:html
/importxml/xhtml:html/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head
/importxml/xhtml:html/xhtml:head/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:head/xhtml:title/jcr:xmltext/jcr:xmlcharacters=Three Namespaces
/importxml/xhtml:html/xhtml:body
/importxml/xhtml:html/xhtml:body/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1/align=center
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/xhtml:h1/jcr:xmltext/jcr:xmlcharacters=An Ellipse and a Rectangle
/importxml/xhtml:html/xhtml:body/svg:svg
/importxml/xhtml:html/xhtml:body/svg:svg/jcr:primaryType=nt:unstructured
/importxml/xhtml:html/xhtml:body/svg:svg/width=12cm
/importxml/xhtml:html/xhtml:body/svg:svg/height=10cm
.
.
.