JBoss.orgCommunity Documentation
Using ModeShape within your application is actually quite straightforward. Although there are multiple ways to access a JCR repository in ModeShape, the simplest is to use the JSR-283 RepositoryFactory interface to get a reference to a named Repository from a configuration file. After that, you continue to work with your repository content using the JCR API.
ModeShape provides an implementation of the RepositoryFactory interface that can return a reference to a named repository based on a provided configuration file. The code to get started with this is very simple.
String configUrl = ... ; // URL that points to your configuration file
Map params = Collections.singletonMap("org.modeshape.jcr.URL", configUrl);
Repository repository;
for (RepositoryFactory factory : ServiceLoader.load(RepositoryFactory.class)) {
repository = factory.getRepository(parameters);
if (repository != null) break;
}
This code looks for all RepositoryFactory implementations on the classpath (assuming those implementations properly defined the service provider within their JARs), and will ask each to create a repository given the supplied parameters. Thus, the parameters are specific to the implementation you want to use.
With JCR 1.0, applications could only find a Repository instance using implementation-specific code. This new JCR 2.0 approach is a bit more complicated, but should work with most JCR 2.0 implementations and does not require using any implementation classes. And your application can even load the parameters from a configuration resource, meaning nothing in your application depends on a particular JCR implementation.
ModeShape uses a single property named "org.modeshape.jcr.URL
"
with a value that is a URL that either resolves to a ModeShape configuration file, such as
file://path/to/configFile.xml?repositoryName=MyRepository
that references a file on the local file system, or
classpath:path/to/configFile.xml?repositoryName=MyRepository
that references a file on the local classpath, or
jndi://name/in/jndi?repositoryName=MyRepository
to point to an existing or JcrEngine
instance registered in JNDI.
Pointing directly to a configuration file often works well in stand-alone applications, while using JNDI works great
for applications deployed to server platforms (e.g., an application server or servlet container) where multiple applications
might want to use the same JCR repository while hiding all of the configuration details from the JCR clients.
We'll see in the next section
how to configure ModeShape's JcrEngine
explicitly and register it in JNDI.
So, here's the ServiceLoader example again, but with ModeShape-specific parameters:
String configUrl = ... ; // URL that points to your configuration file
Map<String,String> parameters = Collections.singletonMap("org.modeshape.jcr.URL", configUrl);
Repository repository = null;
for (RepositoryFactory factory : ServiceLoader.load(RepositoryFactory.class)) {
repository = factory.getRepository(parameters);
if (repository != null) break;
}
Once you've gotten hold of a Repository instance, you can use it to create Sessions, using code similar to:
Credentials credentials = ...; // JCR credentials
String workspaceName = ...; // Name of repository workspace
Session session = repository.login(credentials,workspaceName);
The previous section showed how easy it was to obtain a Repository and Session using the standard JCR API, using a URL to point to an existing configuration file. This section provides an introduction to ModeShape configuration files, although you will likely want to look at the Reference Guide for a more detailed explanation.
Each configuration file defines the components that are used to create the repository:
Repository sources
are the POJO objects that each describe a particular
location where content is stored. Each repository source object is an instance of a ModeShape connector, and is configured
with the properties that particular source. ModeShape's RepositorySource classes are analogous to JDBC's DataSource
classes -
they are implemented by specific connectors (aka, "drivers") for specific kinds of repository sources (aka, "databases").
Similarly, a RepositorySource instance is analogous to a DataSource
instance, with bean properties for each configurable
parameter. Therefore, each repository source definition must supply the name of the RepositorySource class, any
bean properties, and, optionally, the classpath that should be used to load the class.
Repositories
define the JCR repositories that are available. Each
repository has a unique name that is used to obtain the Repository instance,
but each repository definition also can include the predefined namespaces (other than those automatically defined by
ModeShape), various options, and the node types that are to be available in the repository without explicit registration
through the JCR API.
Sequencers
define the particular sequencers that are available for use.
Each sequencer definition provides the path expressions governing which nodes in the repository should be sequenced when those nodes change,
and where the resulting output generated by the sequencer should be placed. The definition also must state the name of
the sequencer class, any bean properties and, optionally, the classpath that should be used to load the class.
MIME type detectors
define the particular MIME type detector(s) that should
be made available. A MIME type detector does exactly what the name implies: it attempts to determine the MIME type given a
"filename" and contents. ModeShape automatically uses a detector that uses the file extension to identify the MIME type,
but also provides an implementation that uses an external library to identify the MIME type based upon the contents.
The definition must state the name of the detector class, any bean properties and, optionally, the classpath that should
be used to load the class.
Creating a ModeShape configuration file is fairly straightforward. Here is the configuration file that is used in the repository example, though it has been simplified a bit and most comments have been removed for clarity):
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns:mode="http://www.modeshape.org/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0">
<!--
Define the JCR repositories
-->
<mode:repositories>
<!--
Define a JCR repository that accesses the 'Cars' source directly.
-->
<mode:repository jcr:name="car repository" mode:source="Cars">
<mode:options jcr:primaryType="mode:options">
<systemSourceName jcr:primaryType="mode:option" mode:value="system@Cars"/>
<jaasLoginConfigName jcr:primaryType="mode:option" mode:value="modeshape-jcr"/>
<!--
As a convenience, ModeShape defaults to granting guest users full access.
In a production system, you would want to limit this access by uncommenting one of the
options below:
for no access:
<anonymousUserRoles jcr:PrimaryType="mode:option" mode:value="" />
for read-only acces:
<anonymousUserRoles jcr:PrimaryType="mode:option" mode:value="readonly" />
-->
</mode:options>
</mode:repository>
</mode:repositories>
<!--
Define the sources for the content. These sources are directly accessible using the ModeShape-specific
Graph API.
-->
<mode:sources jcr:primaryType="nt:unstructured">
<mode:source jcr:name="Cars"
mode:classname="org.modeshape.graph.connector.inmemory.InMemoryRepositorySource"
mode:retryLimit="3" mode:defaultWorkspaceName="workspace1">
<predefinedWorkspaceNames>system</predefinedWorkspaceNames>
</mode:source>
</mode:sources>
<!--
Define the sequencers. This is an optional section.
-->
<mode:sequencers>
<mode:sequencer jcr:name="Image Sequencer"
mode:classname="org.modeshape.sequencer.image.ImageMetadataSequencer">
<mode:description>Image metadata sequencer</mode:description>
<mode:pathExpression>/foo/source => /foo/target</mode:pathExpression>
<mode:pathExpression>/bar/source => /bar/target</mode:pathExpression>
</mode:sequencer>
</mode:sequencers>
<!--
Define how ModeShape will determine the MIME type of files. This is an optional section;
if you do not specify a MIME type detector, ModeShape will use a built-in one that is based
filename extensions for most commonly-used files.
-->
<mode:mimeTypeDetectors>
<mode:mimeTypeDetector jcr:name="Detector"
mode:description="Standard extension-based MIME type detector"/>
</mode:mimeTypeDetectors>
</configuration>
Sometimes your applications can simply define a configuration file and use the RepositoryFactory to access its repositories. This is very straightforward, and this is useful for many simple applications.
Web applications are a different story. Often, you may not want your web application to contain the code that initializes a ModeShape JCR repository. Or, you may want the same repository instance to be reused in multiple web applications deployed to the same web/application server. In these cases, it is possible to configure the web/app server's JNDI instance to instantiate the repository, meaning the web applications need only use the standard JNDI and JCR APIs.
Here's an example of how such a web application would obtain a JCR Repository instance, use it to create a JcrSession
,
and then close the session when completed.
Session session = null;
try {
// Look up the JCR Repository object ...
InitialContext initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Repository repo = (Repository) envCtx.lookup("jcr/local"); // name in JNDI is defined by configuration
// Obtain a JCR Session using simple authentication
// (or use anonymous authentication if desired)
session = repo.login(new SimpleCredentials("username", "password".toCharArray()));
// Use the JCR Session to do something interesting
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (session != null) session.logout();
}
Note that the location of the Repository instance in JNDI depends upon the configuration. In this example, we used
"jcr/local
", but the only requirement is that it match the location where it was placed in JNDI.
We showed how web applications can use an existing Repository instance. In the next section, we describe how to configure the web server so that the Repository instance is available in JNDI.
Each kind of web server or application server is different, but all servlet containers do provide a way of configuring
objects and placing them into JNDI. ModeShape provides a JndiRepositoryFactory
class that implements
and that can be used in the server's configuration. The JndiRepositoryFactory
requires two properties:
configFile
is the path to the
configuration file resource, which must be available on the classpath
repositoryName
is the name of a JCR repository that exists
in the JCR configuration and that will be made available by this JNDI entry
Here's an example of a fragment of the conf/context.xml
for Tomcat:
<Resource name="jcr/local"
auth="Container"
type="javax.jcr.Repository"
factory="org.modeshape.jcr.JndiRepositoryFactory"
configFile="/resource/path/to/configuration.xml"
repositoryName="Test Repository Source" />
Note that it is possible to have multiple Resource
entries. The JndiRepositoryFactory
ensures
that only one JcrEngine
is instantiated, but that a Repository instance is registered for each entry.
Before the server can start, however, all of the ModeShape jars need to be placed on the classpath for the server. JAAS also needs to be configured, and this can be done using the application server's configuration or in your web application if you're using a simple servlet container. For more details, see the Reference Guide.
The ModeShape community has solicited input on how we can make it easier to consume and use ModeShape in applications that do not use Maven. Check out the discussion thread, and please add any suggestions or opinions!
Then, your web application needs to reference the Resource
and state its requirements in its
web.xml
:
<resource-env-ref>
<description>Repository</description>
<resource-env-ref-name>jcr/local</resource-env-ref-name>
<resource-env-ref-type>javax.jcr.Repository</resource-env-ref-type>
</resource-env-ref>
Note that the value of resource-env-ref-name
matches the value of the name attribute on the
<Resource>
tag in the context.xml
described above. This is a must.
At this point, your web application can perform the lookup of the Repository object, create and use a Session, and then close the Session. Here's an example of a JSP page that does this:
<%@ page import="javax.naming.*, javax.jcr.*, org.jboss.security.config.IDTrustConfiguration" %>
<%!
static {
// Initialize IDTrust
IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
try {
idtrustConfig.config("security/jaas.conf.xml");
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
%>
<%
Session sess = null;
try {
InitialContext initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
Repository repo = (Repository) envCtx.lookup("jcr/local");
sess = repo.login(new SimpleCredentials("readwrite", "readwrite".toCharArray()));
// Do something interesting with the Session ...
out.println(sess.getRootNode().getPrimaryNodeType().getName());
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (sess != null) sess.logout();
}
%>
Since this uses a servlet container, there is no JAAS implementation configured, so note the
loading of IDTrust to create the JAAS realm. (To make this work in Tomcat, the security
folder that contains the jaas.conf.xml
, users.properties
, and
roles.properties
needs to be moved into the %CATALINA_HOME%
directory.)
If you use an application server such as JBoss EAP, you could just configure the JAAS realm as part of the server configuration and be done with it.
Before you deploy ModeShape into your application or its environment, you need to make sure that all of the ModeShape JARs are on the appropriate classpath. Two different scenarios are covered in this section: Maven-based, and using JARs with the traditional classpath.
By far the easiest way to use ModeShape is to use Maven, because with just a few lines of code, Maven will automatically pull all the JARs and source for all of the ModeShape libraries as well as everything those libraries need. All of ModeShape's artifacts for each release are published in the new JBoss Maven repository under the "org.modeshape" group ID.
The JBoss Maven repository not only contains all of the artifacts for ModeShape and other open source projects hosted at JBoss.org, but it also proxies quite a few other repositories that contain many other third-party libraries.
So if you're using Maven (or Ivy), first make sure your project knows about this new JBoss Maven repository. One way to do this is to add the following to your project POM (you'll still likely want to use other Maven repositories for third-party artifacts):
<repositories>
<repository>
<id>jboss</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
</repositories>
Or, you can add this information to your ~/.m2/settings.xml
file. For more information,
see the JBoss wiki page.
Then, simply modify your project's POM by adding dependencies on the ModeShape JCR library:
<dependency>
<groupId>org.modeshape</groupId>
<artifactId>modeshape-jcr</artifactId>
<version>2.0.0.Final</version>
</dependency>
This adds only the minimal libraries required to use ModeShape, so you need to add dependencies for each of the connectors and sequencers you want to use. Here is the list of available sequencers:
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-cnd</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-ddl</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshapce</groupid>
<artifactid>modeshape-sequencer-images</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-classfile</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-java</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-mp3</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-msoffice</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-xml</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-text</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-sequencer-zip</artifactid>
<version>2.0.0.Final</version>
</dependency>
Here is the list of available connectors:
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-filesystem</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-infinispan</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-jcr</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-jbosscache</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-jdbc-metadata</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-store-jpa</artifactid>
<version>2.0.0.Final</version>
</dependency>
<dependency>
<groupid>org.modeshape</groupid>
<artifactid>modeshape-connector-svn</artifactid>
<version>2.0.0.Final</version>
</dependency>
The sequencer and connector libraries you choose, plus every third-party library they need, will be pulled in automatically by Maven into your project.
ModeShape is designed to use the same logging framework as your application, and it uses SLF4J to accomplish this. In other words, ModeShape depends upon the SLF4J API library, but requires you to provide provide a logging implementation as well as the appropriate SLF4J binding JAR.
For example, if your application is using Log4J, your application will already have a dependency for it, and so ModeShape log messages will be sent to the same logging system used in your application, you need to add a dependency to the SLF4J-to-Log4J binding JAR:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.11</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
Of course, SLF4J works with other logging frameworks, too. Some logging implementations (such as LogBack) implement the SLF4J API natively, meaning they require no binding JAR. For details on the options and how to configure them, see the SLF4J manual.
If your application doesn't use Maven, you'll need to obtain the ModeShape JARs and place them onto your application's classpath. ModeShape provides a single download with all of the JARs for all ModeShape components and all dependencies. This file contains the following:
modeshape-jcr-2.0.0.Final-with-dependencies.jar
contains the JARs
necessary to run the core ModeShape JCR repository engine,
the in-memory connector, and the federating connector;
one modeshape-connector-<type>-2.0.0.Final-with-dependencies.jar
for each type of connector, each containing the JARs necessary
for that connector;
one modeshape-sequencer-<type>-2.0.0.Final-with-dependencies.jar
for each type of sequencer, each containing the JARs necessary
for that sequencer;
modeshape-mimetype-detector-aperture-2.0.0.Final-with-dependencies.jar
contains all of the JARs required for the component that detects
the MIME type of files based upon names and/or content; and
modeshape-jpa-ddl-gen-2.0.0.Final-jar-with-dependencies.jar
contains all of the JARs required to run the DDL generation utility.
Note that the core engine is required in all configurations. The jcr-2.0.jar
file is not included and must be provided by you.
And, as mentioned in the previous section, ModeShape uses SLF4J for logging and you must provide
a logging implementation as well as the appropriate SLF4J binding JAR.
This chapter outline how you configure ModeShape, how you then access a javax.jcr.Repository
instance,
and use the standard JCR API to interact with the repository. The
next chapter walks you through downloading
and building the ModeShape examples, while Chapter 5
and Chapter 6 shows how to run the examples.