Using ModeShape within your application is actually quite straightforward. Simply configure ModeShape with one or more repositories and the sources where the content for those repositories should be accessed and stored. Then, your application just uses the JCR 2.0 API to connect to and use those repositories.
Before we dive into how to configure ModeShape, let's start by looking at how your application will find and use the JCR repositories.
The latest version of the JCR 2.0 API specification (JSR-283) defines a RepositoryFactory interface that when coupled with the Java Standard Edition Service Loader mechanism lets your application find JCR Repository instances using only the JCR API and Java interfaces, without using any implementation-specific interfaces.
ModeShape supports and recommends using this approach, which looks like this:
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. The first factory that understands these parameters will return a Repository instance, while other factories will return null. The key, then, for defining which JCR Repository implementation your application uses are the parameters passed to the getRepository(Map) method. Simply load these from a properties file, and your application is set.
|This RepositoryFactory approach is new to JCR 2.0. With JCR 1.0, your application likely used specific classes from the implementation to instantiate a Repository implementation.|
Once you've gotten hold of a Repository instance, you can use it to create Sessions. JCR sessions are lightweight, so creating them is very fast. But they are not thread safe, so they shouldn't be used concurrently by multiple threads. Therefore, the JCR specification recommends applications create sessions to read, query or change repository content, and then quickly close the sessions:
JCR sessions are stateful, meaning they cache any information that is accessed to provide a single consistent view of the content, including any transient changes that haven't yet been saved. Thus, in applications with many concurrent sessions changing content, the cached data of a longer-lived session can become inconsistent with the stored content, and must be manually refreshed using the Session's refresh() method. It is for this reason that the JCR specification recommends using short-lived sessions.
Observing the repository for changes, however, will require registering listeners with a session, and will only receive events while that session is alive. Therefore, observation requires a longer-lived session. But the recommendation is that these longer-lived sessions are used only to register your application's listeners, and not used to read or update content.
These are the basics of writing an application that uses JCR. Next, we'll start looking at the specifics of ModeShape, starting with those RepositoryFactory properties.
ModeShape's RepositoryFactory implementation looks for a single property named "org.modeshape.jcr.URL". The value of this property is most often a URL pointing to a ModeShape configuration file, which is on the local file system at an absolute path:
or a path relative to the running application:
The configuration file can even be accessed from a web service (e.g., a web server, WebDAV, or version control system) using any resolvable URL, such as:
This works great for self-contained applications, because ModeShape will create a new repository engine that runs embedded in the application. However, applications running in platforms (such as servlet containers or Java application servers) will likely prefer that ModeShape runs as a central service in the platform that can be shared by multiple applications. In these cases, the ModeShape engine will already be running and registered in JNDI, so the application will use a URL that points to this JNDI location:
Here's an example of a property file containing the single ModeShape property for RepositoryFactory:
In the next section, we'll take an introductory look at what these configuration files look.
The previous section showed how easy it was to obtain a Repository and Session using the standard JCR API. This section provides an introduction to ModeShape configuration files, although you will likely want to look at the Reference Guide for more detail.
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.
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):
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 because the application will then own the ModeShape instance(s).
Web applications are a different story. Often, you would rather your web application not contain the code that initializes the JCR repository, but instead configure ModeShape as a central, shared service that all of your web applications can simply reference and use.
Unfortunately, there's no common way to deploy ModeShape into the various web or application servers, since they all have slightly different deployment and configuration techniques. The remainder of this section will talk about how to deploy ModeShape to two popular open source servers, the JBoss Application Server and Apache Tomcat.
The JBoss Application Server (or JBoss AS) is a very popular open source Java application server, with an extremely healthy and active community. ModeShape offers a way to deploy ModeShape into JBoss AS as as a central, shared service that can be monitored and administered using the embedded console.
ModeShape provides a downloadable ZIP file that can be unzipped into any JBoss AS profile. When you do this, that profile will contain all the files necessary for ModeShape to run when the server is started. The default configuration is for a single, in-memory repository with two users. However, other than basic playing, you will want to edit the configuration files to define a more robust, persistent and secure configuration.
This JBoss AS distribution ZIP file contains several components:
- JAR files for the JCR 2.0 API and ModeShape's small extensions to the JCR API on the global classpath (that is, in the "lib/" directory). These APIs are available to all deployed applications, services and components. The JCR API contains the "javax.jcr" packages and has no other dependencies. ModeShape's extensions define interfaces in the "org.modeshape.jcr.api" packages; these extend a few of the standard JCR API interfaces and add several methods to make them more useful.
- The ModeShape Service, represented as an exploded JAR file in the "deploy" directory. This is where the JcrEngine is running, though any application (or other JBoss service) can access its JCR Repository instances using the standard RepositoryFactory approach described earlier by using a URL such as:
By default, there is a single in-memory repository named "repository", but this can be changed by simply editing the "deploy/modeshape-services.jar/managedConfigRepository.xml" configuration file. All of ModeShape's standard sequencers and connectors (and JARs for their dependencies) are included, meaning they can be configured for use without worrying about adding JARs to the classpath. Feel free to remove any of the JARs are not needed for your custom configuration.
- A pair of JAAS properties files, located in the "conf/props/" directory, that come out of the box with an "admin" user (with password "admin") that has full read, write, and administration privileges, and a "guest" user (with password "guest") that has only read and write privileges. Simply edit these files to change users, passwords, and roles, or to configure JAAS differently.
- The ModeShape RESTful API, represented as an exploded WAR file in the "deploy" directory. This allows remote applications to interact with ModeShape to access and manipulate repository content using a RESTful API that uses JSON in the requests and responses. All ModeShape repositories can be accessed, and authentication is done using the ModeShape JAAS configuration.
- The ModeShape WebDAV API, represented as an exploded WAR file in the "deploy" directory. This web application allows external clients to access and manipulate the content in the ModeShape repositories using the standard WebDAV protocol. For example, you can mount a repository (or parts of it) as a network drive on most operating systems, and then upload or download files and folders using standard OS operations and graphical tools. All ModeShape repositories can be accessed, and authentication is done using the ModeShape JAAS configuration.
- A plugin for the embedded JBoss AS console, represented as a WAR file in the "deploy" directory. This plugin also works with RHQ administration, monitoring, alerting, operational control and configuration system. This feature is currently incomplete, but is undergoing active development.
- A JDBC driver for querying the repositories through JDBC. This driver is on the global classpath so it can be used in any deployed component. A single JDBC DataSource is also configured in the "deploy/modeshape-services.jar/modeshape-jdbc-ds.xml" file to use the single default in-memory repository available out of the box. Simply edit this file to add or change the DataSource definitions.
Here are the contents of this file:
Your web application or JBoss service can use one of the JCR Repository instances running inside the ModeShape service by simply using the RepositoryFactory technique described earlier, with a URL such as:
Be sure to use the correct repository name.
Since the JCR API JAR is on the global classpath, your web application can use the JCR API without having to include the JAR file in your application's WAR file. In fact, your application will likely get ClassCastExceptions if it does include the JCR API in its WAR file. Plus, if needed, your application can use ModeShape's "org.modeshape.jcr.api" extensions to the JCR API (again, on the global classpath), and should not need or use any of the classes or interfaces in the ModeShape implementation.
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:
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:
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 by using JNDI directly (or the more standard RepositoryFactory technique shown earlier), create and use a Session, and then close the Session. Here's an example of a JSP page that does this:
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 deploy your application to JBoss AS or EAP and deploy ModeShape as a service, your application doesn't have to do anything with JAAS, since that's provided by the platform.|
Deploying ModeShape as a service in JBoss AS is all set up with the correct classpaths and configurations. In other deployments, you'll have to ensure that all of the ModeShape JARs are available on the appropriate classpath. This section describes two different scenarios for doing this: 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):
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:
This adds only the minimal libraries required to use ModeShape. If your application is going to use clustering, you'll need to also depend upon the clustering module:
You also need to add dependencies for each of the connectors and sequencers you want to use. Here is the list of available sequencers:
Here is the list of available connectors:
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:
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.7-jar-with-dependencies.jar contains all of the classes (except those under javax.jcr) necessary to run the core ModeShape JCR repository engine using the in-memory connector and the federating connector;
- one modeshape-connector-<type>-2.7-jar-with-dependencies.jar for each type of connector, each containing all of the classes necessary for that connector, designed to be added to the classpath after the modeshape-jcr-2.7-jar-with-dependencies.jar file;
- one modeshape-sequencer-<type>-2.7-jar-with-dependencies.jar for each type of connector, each containing all of the classes necessary for that sequencer, designed to be added to the classpath after the modeshape-jcr-2.7-jar-with-dependencies.jar file;
- modeshape-mimetype-detector-aperture-2.7-jar-with-dependencies.jar containing all of the classes necessary for detecting the MIME type of files based upon their name and/or content, designed to be added to the classpath after the modeshape-jcr-2.7-jar-with-dependencies.jar file;
- modeshape-jpa-ddl-gen-2.7-jar-with-dependencies.jar contains all of the classes required to run the DDL generation utility as a standalone application.
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.