JBoss.orgCommunity Documentation
The Content Repository for Java technology API provides a standard Java API for working with content repositories. Abbreviated "JCR", this API was developed as part of the Java Community Process under JSR-170 (JCR 1.0) and is being revised under JSR-283. JBoss DNA provides a partial JCR 1.0 implementation that allows you to work with the contents of a repository using the JCR API. For information about how to use the JCR API, please see the JSR-170 specification.
In the interests of brevity, this chapter does not attempt to reproduce the JSR-170 specification nor provide an exhaustive definition of JBoss DNA JCR capabilities. Rather, this chapter will describe any deviations from the specification as well as any DNA-specific public APIs and configuration.
Using JBoss DNA within your application is actually quite straightforward. As you'll see in this chapter,
the first step is setting up JBoss DNA and starting the JcrEngine
. After that, you obtain the
javax.jcr.Repository
instance for a named repository and just use the standard JCR API throughout your
application.
Once you've obtained a reference to a JcrEngine
as described in
the previous chapter, obtaining a repository is as easy as calling
the getRepository(String)
method with the name of the repository that you just configured.
String repositoryName = ...;
JcrEngine
jcrEngine = ...;
Repository repository = jcrEngine.getRepository(repositoryName);
At this point, your application can proceed by working with the JCR API.
Once you have obtained a reference to the JCR Repository, you can create a JCR session using one of its
login(...)
methods. The JSR-170 specification provides four login methods.
The first method allows the implementation to choose its own security context to create a session in the default workspace
for the repository. The JBoss DNA JCR implementation uses the security context from the current AccessControlContext
. This implies
that this method will throw a LoginException if it is not executed as a PrivilegedAction
. Here is one example of how this might
work:
Subject subject = ...; Session session = (Session) Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() { public Session run() throws Exception { return repository.login(); } }, AccessController.getContext());
This approach will yield a session with the same user name and roles as subject
. There is a comparable
version of login(...)
that allows the workspace to be specified by name.
Subject subject = ...; final String workspaceName = ...; Session session = (Session) Subject.doAsPrivileged(subject, new PrivilegedExceptionAction<Session>() { public Session run() throws Exception { return repository.login(workspaceName); }}, AccessController.getContext());
It is also possible to supply the Credentials directly as part of the login process, although JBoss DNA imposes some requirements on what types of Credentials may be supplied. The simplest way is to provide a SimpleCredentials object. These credentials will be validated against the JAAS realm named "dna-jcr" unless another realm name is provided as an option during the JCR repository configuration. For example:
String userName = ...; char[] password = ...; Session session = repository.login(new SimpleCredentials(userName, password));
The credentials-based login(...)
method also supports an optional workspace name.
String userName = ...; char[] password = ...; String workspaceName = ...; Session session = repository.login(new SimpleCredentials(userName, password), workspaceName);
If a LoginContext
is available for the user, that can be used as part of the credentials to authenticate the user with
JBoss DNA instead. This snippet uses an anonymous class to provide the login context, but any class with a
method can be used as well.
LoginContext
getLoginContext()
finalLoginContext
loginContext = ...; Session session = repository.login(new Credentials() {LoginContext
loginContext getLoginContext() { return loginContext; } }, workspaceName);
Servlet-based applications may wish to reuse the authentication information from HttpServletRequest
instead. Please note that
the example below assumes that the servlet has a security constraint that prevents unauthenticated access.
HttpServletRequest
request = ...; ServletSecurityContext securityContext = new ServletSecurityContext(request); Session session = repository.login(newSecurityContextCredentials
(securityContext);
Once the Session is obtained, the repository content can be accessed and modified like any other JCR repository. No roles are required to connect
to any workspace at this time. Restrictions on workspace connections will likely be added to JBoss DNA in the near future. The roles from the JAAS
information or the HttpServletRequest
are used to control read and write access to the repository. Please see the JCR Security section
for more details on how access is controlled.
The JBoss DNA JCR implementation will not be JCR-compliant prior to the 1.0 release. Additionally, the JCR specification allows some latitude to implementors for some implementation details. The sections below clarify JBoss DNA's current and planned behavior.
JBoss DNA currently supports most of the Level 1 and Level 2 feature set defined by the JSR-170 specification.
Queries, which are part of Level 1, are not implemented. Some of the L2 features such as workspace cloning and updating, corresponding nodes,
and referential integrity for REFERENCE
properties are also not yet implemented. As the current implementation does provide many
of the features that may be needed by an application, we really hope that this release will allow you to give us some feedback on what we have so far.
JBoss DNA does not currently support any of the optional JCR features. Currently, the observation optional feature is planned to be complete prior to the 1.0 release. The locking optional feature may be implemented in this timeframe as well.
The JCR-SQL optional feature is not planned to be implemented as it has been dropped from the JSR-283 specification.
Although the JSR-170 specification requires implementation of the Session.checkPermission(String, String)
method,
it allows implementors to choose the granularity of their access controls. JBoss DNA supports coarse-grained, role-based access control at the repository
and workspace level.
JBoss DNA currently defines two permissions: READONLY
and READWRITE
. If the Credentials passed into Session.login(...)
(or the Subject
from the AccessControlContext
, if one of the no-credential login
methods were used) has either role, the session will have
the corresponding access to all workspaces within the repository. That is, having the READONLY
role implies that Session.checkPermission(path, "read")
will not throw an AccessDeniedException for any value of path
in any workspace in the repository. Similarly, having the READWRITE
role implies that Session.checkPermission(path, actions)
will not throw an AccessDeniedException for any values of path
and
actions
.
In this release, JBoss DNA does not properly check for actions or even check that the actions
parameter passed into
Session.checkPermission(...)
is even valid. This will be corrected prior to the 1.0 release.
It is also possible to grant access only to one or more named workspaces. For a workspace named "staging", this can be done by assigning a role named
READONLY.staging
. Appending "." + workspaceName
to the READWRITE
role works as well.
As a final note, the JBoss DNA JCR implementation will likely have additional security roles added prior to the 1.0 release. A CONNECT
role
is already being used by the DNA REST Server to control whether users have access to the repository through that means.
JBoss DNA supports all of the built-in node types described in the JSR-170 specification. However, several of these node types (mix:lockable, mix:versionable, nt:version, nt:versionLabels, nt:versionHistory, and nt:frozenNode) are semantically meaningless as JBoss DNA does not yet support the locking or versioning optional features.
Although JBoss DNA does define some custom node types in the dna
namespace, none of these
node types are intended to be used by developers integrating with JBoss DNA and may be changed or removed
at any time.
Although the JSR-170 specification does not require support for registration of custom types, JBoss DNA supports this extremely useful feature. Custom node types can be added at startup, as noted above or at runtime through a DNA-specific interface. JBoss DNA supports defining node types either through a JSR-283-like template approach or through the use of Compact Node Definition (CND) files. Both type registration mechanisms are supported equally within JBoss DNA, although the CND approach for defining node types is recommended.
JBoss DNA also supports defining custom node types to load at startup. This is discussed in more detail in the next chapter.
Although the JSR-283 specification is not yet final, it does provide a useful means of programatically defining JCR node types. JBoss DNA supports a comparable
node type definition API that implements the functionality from the specification, albeit with classes in an org.jboss.dna.jcr
package. The intent
is to deprecate these classes and replace their usage with the JSR-283 equivalents after JBoss DNA fully supports in the JSR-283 specification in a future release.
Node types can be defined like so:
Session session = ... ;
NodeTypeManager nodeTypeManager = session.getWorkspace().getNodeTypeManager();
// Declare a mixin node type named "searchable" (with no namespace)
NodeTypeTemplate nodeType = nodeTypeManager.createNodeTypeTemplate();
nodeType.setName("searchable");
nodeType.setMixin(true);
nodeType.getNodeDefinitionTemplates().add(childNode);
// Add a mandatory child named "source" with a required primary type of "nt:file"
NodeDefinitionTemplate childNode = nodeTypeManager.createNodeDefinitionTemplate();
childNode.setName("source");
childNode.setMandatory(true);
childNode.setRequiredPrimaryTypeNames(new String[] { "nt:file" });
childNode.setDefaultPrimaryType("nt:file");
// Add a multi-valued STRING property named "keywords"
PropertyDefinitionTemplate property = nodeTypeManager.createPropertyDefinitionTemplate();
property.setName("keywords");
property.setMultiple(true);
property.setRequiredType(PropertyType.STRING);
nodeType.getPropertyDefinitionTemplates().add(property);
// Register the custom node type
nodeTypeManager.registerNodeType(nodeType);
Residual properties and child node definitions can also be defined simply by not calling setName
on
the template.
Custom node types can be defined more succinctly through the Compact Node Definition file format. In fact, this is how JBoss DNA defines its built-in node types. An example CND file that declares the same node type as above would be:
[searchable] mixin - keywords (string) multiple + source (nt:file) = nt:file
This definition could then be registered with the following code snippet.
String pathToCndFileInClassLoader = ...;
CndNodeTypeSource nodeTypeSource = new CndNodeTypeSource(pathToCndFileInClassLoader);
for (Problem problem : nodeTypeSource.getProblems()) {
System.err.println(problem);
}
if (!nodeTypeSource.isValid()) {
throw new IllegalStateException("Problems loading node types");
}
Session session = ... ;
NodeTypeManager nodeTypeManager = session.getWorkspace().getNodeTypeManager();
nodeTypeManager.registerNodeTypes(nodeTypeSource);
JBoss DNA does not yet support a simple means of unregistering types at this time, so be careful before registering types outside of a sandboxed environment.
In this chapter, we covered how to use JCR with JBoss DNA and learned about how it implements the JCR specification. Now that you know how JBoss DNA repositories work and how to use JCR to work with DNA repositories, we'll move on in the next chapter to show how you can use the RESTful web service to provide access to the content in a JCR repository to clients.